티스토리 뷰

발생일: 2009.12.17

문제:
이번 연구회 때 발표할 주제는 AJAX 다.
대부분 신입 사원들이라 XMLHttpRequest 객체 생성부터 다뤄보려고 한다.

얼마 전 읽은 John Resig 의 Pro Javascript Techniques 책에서 생성하는 방식으로 설명할까 하다가,
신입사원들이 알기에는 좀 어려울 것 같다는 생각이 들어 다른 튜토리얼이나 라이브러리 소스를 좀 열어봤다.
대부분 비슷하긴 한데, 다들 구현하는 방식이 조금씩 다르다.

그렇다면 어떤 방법으로 구현하는 게 가장 좋을까?


해결책:
일단 XMLHttpRequest 객체에 대해 간단하게 히스토리를 정리해보자.

비동기 통신 수단인 XMLHttp 는 인터넷 익스플로러에서 제일 먼저 제안하였으며,
최초 ActiveXObject 를 사용해서 구현하였다.

그 후, W3C 에서 XMLHttpRequest 객체를 표준으로 정의하였고,
다른 브라우저들은 대부분 XMLHttpRequest 객체를 사용하여 연결하고 있다.
결국 대세(?)에 따라 인터넷 익스플로러도 버전 7부터는 XMLHttpRequest 객체를 기본으로 지원한다.

하지만, 아직까지는 IE6 등 구 버전의 인터넷 익스플로러를 사용하는 사용자가 많기 때문에,
IE는 다른 브라우저들과 다른 방법으로 XMLHttpRequest 를 생성해야 한다.


결국, 인터넷 익스플로러는 IE6 이하 버전은 ActiveXObject 객체를 통해서 생성하고,
IE7 이상 버전이나 다른 브라우저들은 XMLHttpRequest 객체를 바로 생성하면 된다.

여기서는 'XMLHttpRequest 를 어떻게 크로스 브라우징이 가능하게 생성할 것인가?' 에 대해,
어떤 방법이 쉽고 간편할 지, 그 장단점을 중점으로 다뤄보려고 한다.


1. createXMLHttp() 함수를 만들어 버전별로 생성하기
가장 기본적인 방법은 아래와 같이 XMLHttpRequest 객체를 얻는 함수를 만들어 생성하는 방법이다.

IE의 ActiveXObject 로 구현되어 있는 XMLHttpRequest 객체에는 여러 버전이 있는데,
큰 차이점은 없으나 안정성이나 속도 면에서 최근 버전을 쓰는 게 좋겠다.
아쉽게도 ActiveX 컨트롤이 지원하는 XMLHttp 객체의 버전을 바로 알아낼 수 없기 때문에,
최신 버전부터 각각 try - catch 구문으로 시도해보아야 한다.

    function createXMLHttp() {
        // XMLHttpRequest 가 가능하면 바로 리턴한다
        if (typeof XMLHttpRequest != 'undefined') {
            return new XMLHttpRequest();
        }
   
        // 사용 가능한 XMLHttp 버전 목록
        var versions = [
             'Msxml2.XMLHTTP.5.0',
             'Msxml2.XMLHTTP.4.0',
             'Msxml2.XMLHTTP.3.0',
             'Msxml2.XMLHTTP',
             'Microsoft.XMLHttp'            
        ];
       
        // 최신 버전 순서대로 가능한 버전으로 생성한다.
        for (var i = 0; i < versions.length; i++) {
            try {
                return new ActiveXObject(versions[i]);
             } catch (e) {
                 // do nothing
            }
        }
        throw new Error('This browser does not support XMLHttpRequest');
    }
   
    var xhr = createXMLHttp(); // 함수를 통해 객체를 생성한다.


이 방법은 (구문과 체크하는 대상 버전은 약간 다르지만) prototypejs 라이브러리에서도 사용하고 있다.

브라우저에서 지원하는 최신 버전의 ActiveXObject 를 얻어올 수 있지만,
매 요청마다 try - catch 를 하는 것이 좀 비효율적이지 않을까라는 생각이 든다.


2. XMLHttpRequest 생성자에 wrapper 생성하기
문제점에서 언급했던 책(프로 자바스크립트 테크닉)에 있던 방법이다.
브라우저에서 XMLHttpRequest 가 지원되지 않으면, ActiveXObject 리턴하는 래퍼를 생성한다.

주목해 볼 점은, 1번에서처럼 모든 버전을 try - catch 로 체크하는 게 아니라,
navigator 속성을 가져와 IE 5 버전일 경우와 아닌 경우로 나눠,
Microsoft.XMLHTTP 와 Msxml2.XMLHTTP 로 생성한다는 점이다.

현재 버전의 jquery 에서는 다른 방법으로 구현하고 있지만,
책을 쓴 저자가 jquery 를 만든 사람이니(John Resig), 아마 초기 jquery 버전에 사용되지 않았을까... 생각해본다.

    if (typeof XMLHttpRequest == 'undefined') { // XMLHttpRequest 가 없을 경우
        // XMLHttpRequest 에 대한 wrapper 생성
        XMLHttpRequest = function() {
            return new ActiveXObject(
                // IE 5 버전일 경우와 아닌 경우로 나누어 리턴한다
                navigator.userAgent.indexOf('MSIE 5') > -1 ?
                'Microsoft.XMLHTTP' : 'Msxml2.XMLHTTP'
            );
        };
    }
   
    var xhr = new XMLHttpRequest(); // XMLHttpRequest 객체를 생성한다.


이 방법은 기본 XMLHttpRequest 객체를 생성하는 방법과 동일하게 생성자를 호출하면 되므로,
객체 생성 시 가독성이 좋을 수 있겠다.
또한 브라우저 초기화 시에 생성자에 대한 래퍼를 정의해 놓는다면, 사용할 때 더욱 편리하지 않을까 싶다.

하지만 1번 방법과 다르게 최신 버전의 ActiveXObject 를 제공하지는 않는다.
대신 1번처럼 try - catch 를 사용하여 부담을 주는 대신 navigator 의 속성을 이용하고 있으므로,
ActiveXObject 의 어떤 버전을 가져올 지에 대한 효율적인 선택이라고 생각한다.


3. window.ActiveXObject 지원 여부로 사용하기
가장 간단하면서도 정상적으로 작동하도록 할 수 있는 방법이다.
버전에 상관없이 ActiveXObject 만 지원하면 바로 Microsoft.XMLHTTP 를 생성하도록 한다.

    var xhr = window.ActiveXObject ? new ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest();


기존 1, 2번 코드에서 XMLHttpRequest 객체를 지원하는지 여부를 먼저 확인해보고
우선적으로 XMLHttpRequest 객체를 생성했던 것과 달리,
이 방법에서는 window 에서 ActiveXObject 를 지원하는지 여부를 먼저 검토한다.

이 차이점은 IE7 상위 버전에서 테스트 해볼 경우 알 수 있는데,
IE7 부터는 ActiveXObject 와 XMLHttpRequest 객체를 모두 지원하고 있기 때문이다.
IE7 에서 동작시켜 볼 경우, 1, 2번 코드에서는 XMLHttpRequest 객체를 바로 얻어왔다면
이 코드를 통해서는 ActiveXObject 컨트롤을 통해 얻어올 것이다.

이 코드는 현재 jquery(버전 1.3.2)에 구현되어 있는 방법인데,
마이크로소프트가 IE7 에서 XMLHttpRequest 의 적합한 구현에 실패했기 때문에,
ActiveXObject 가 가능할 경우 먼저 사용한다고 주석이 붙어있다.



결론

사실 어떤 방법을 쓰던 작동이나 성능에는 크게 영향을 끼칠 것 같진 않다.
다만 개인적으로는 1번 방법처럼, try - catch 구문으로 모든 버전을 체크하는 것보다는,
아래와 같이 2번과 3번 방법을 적절히 섞어 사용하면 가장 효율적이지 않을까 싶다.

        // ActiveXObject 가 가능할 경우, XMLHttpRequest 에 대한 래퍼를 생성한다.
        // (물론, 이 부분이 ajax 모듈 함수 내에서 정의되어 사용되긴 하겠지만)
        // 래퍼 생성 부분은 ajax 초기화 함수에 넣어두고, onload 이벤트 핸들러에 추가해두는 건 어떨까?
        if (typeof ActiveXObject != 'undefined') {
            XMLHttpRequest = function() {
                return new ActiveXObject(
                    // IE 5 버전일 경우와 아닌 경우로 나누어 리턴한다
                    navigator.userAgent.indexOf('MSIE 5') > -1 ?
                    'Microsoft.XMLHTTP' : 'Msxml2.XMLHTTP'
                );               
            };
        }
       

        // 래퍼가 정의되어 있다면, 어떤 브라우저에서든 아래와 같이 생성하면 된다.
        var xhr = new XMLHttpRequest();




참고:
  Book : John Resig, Pro Javascript Techniques
  XMLHttp Requests for Ajax
반응형
댓글
공지사항