>  기사  >  웹 프론트엔드  >  네이티브 js에서 AJAX, JSONP 및 DOM 로딩 완료 이벤트를 구현하는 방법

네이티브 js에서 AJAX, JSONP 및 DOM 로딩 완료 이벤트를 구현하는 방법

伊谢尔伦
伊谢尔伦원래의
2016-11-21 14:47:421016검색

1. JS 네이티브 Ajax

ajax: 전체 페이지를 새로 고치지 않고 데이터를 요청하는 방법
ajax의 기술 핵심은 XMLHttpRequest 객체입니다.
ajax 요청 프로세스입니다. , 서버에 연결하고 요청을 보내고 응답 데이터를 받습니다.

다음은 나중에 설명할 함수를 간단히 요약한 것입니다.

  ajax({
        url: "./TestXHR.aspx",              //请求地址
        type: "POST",                       //请求方式
        data: { name: "super", age: 20 },        //请求参数
        dataType: "json",
        success: function (response, xml) {
            // 此处放成功后执行的代码
        },
        fail: function (status) {
            // 此处放失败后执行的代码
        }
    });

    function ajax(options) {
        options = options || {};
        options.type = (options.type || "GET").toUpperCase();
        options.dataType = options.dataType || "json";
        var params = formatParams(options.data);

        //创建 - 非IE6 - 第一步
        if (window.XMLHttpRequest) {
            var xhr = new XMLHttpRequest();
        } else { //IE6及其以下版本浏览器
            var xhr = new ActiveXObject('Microsoft.XMLHTTP');
        }

        //接收 - 第三步
        xhr.onreadystatechange = function () {
            if (xhr.readyState == 4) {
                var status = xhr.status;
                if (status >= 200 && status < 300) {
                    options.success && options.success(xhr.responseText, xhr.responseXML);
                } else {
                    options.fail && options.fail(status);
                }
            }
        }

        //连接 和 发送 - 第二步
        if (options.type == "GET") {
            xhr.open("GET", options.url + "?" + params, true);
            xhr.send(null);
        } else if (options.type == "POST") {
            xhr.open("POST", options.url, true);
            //设置表单提交时的内容类型
            xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            xhr.send(params);
        }
    }
    //格式化参数
    function formatParams(data) {
        var arr = [];
        for (var name in data) {
            arr.push(encodeURIComponent(name) + "=" + encodeURIComponent(data[name]));
        }
        arr.push(("v=" + Math.random()).replace("."));
        return arr.join("&");
    }

생성

1.1, IE7 및 그 이전 버전에서는 기본 XHR 객체를 지원하므로 직접 사용할 수 있습니다. var oAjax = new XMLHttpRequest();

1.2, IE6 및 이전 버전에서는 XHR 객체가 ActiveX를 통해 구현됩니다. MSXML 라이브러리의 개체입니다. 일부 책에서는 IE에 있는 이러한 개체의 세 가지 버전, 즉 MSXML2. =new ActiveXObject('Microsoft.XMLHTTP');

2. 연결 및 전송

2.1. () 기능: 요청 방법, 요청 주소, 비동기 요청 여부(동기 요청은 드물고 지금까지 사용되지 않음)

2.2. GET 요청 방법은 URL 매개변수를 통해 서버에 데이터를 제출합니다. POST는 전송 매개변수로 데이터를 서버에 제출합니다.

2.3. POST 요청에서 데이터를 보내기 전에 양식 제출의 내용 유형을 설정해야 합니다.

2.4. 서버는 encodeURIComponent() 메소드로 인코딩되어야 합니다. 실제로 매개변수 목록 "key=value"에서는 키와 값이 모두 특수 문자를 포함하므로 인코딩되어야 합니다. 요청이 이루어질 때마다 "v=xx" 문자열이 매개변수 목록에 입력됩니다. 이는 캐싱을 거부하고 매번 서버에 직접 요청하는 것입니다.

encodeURI(): 전체 URI를 인코딩하는 데 사용되며 콜론, 슬래시, 물음표 및 파운드 기호와 같은 URI에 속하는 특수 문자는 인코딩하지 않습니다. 해당 디코딩 함수 decodeURI() ;
encodeURIComponent(): URI의 특정 부분을 인코딩하는 데 사용되며, 해당 디코딩 함수 decodeURIComponent()를 인코딩합니다.

3.1. 응답을 받은 후 응답 데이터는 자동으로 "text/xml" 또는 "application/xml"을 채우고 이 속성은 XML에 해당하는 문서 유형인 해당 xml 데이터를 저장합니다. 상태: 응답 HTTP 상태 코드;

statusText: HTTP 상태 설명 ;

3.2. XHR 객체의 ReadyState 속성은 요청/응답 프로세스의 현재 활성 단계를 나타냅니다. 속성은 다음과 같습니다
0 - 초기화되지 않았으며 open() 메서드가 호출되지 않았습니다.
1-Start, open() 메서드가 호출되었지만 send() 메서드가 호출되지 않았습니다. 🎜> 2-보내기, send() 메소드가 호출되었지만 응답이 수신되지 않았습니다.

3-수신, 응답 데이터의 일부가 수신되었습니다.

4-완료, 모든 응답 데이터가 수신되었습니다.

readyState의 값이 변경되는 한 Readystatechange 이벤트가 호출됩니다. (사실 논리적인 원활함을 위해 요청은 전송 중에 이루어지기 때문에 전송 후에 배치할 수 있습니다. 서버는 네트워크 통신을 수행하는데 시간이 소요됩니다.전송 후에 Readystatechange 이벤트 핸들러를 지정하는 것도 가능합니다. 저는 보통 이런 방식으로 사용하지만, 표준화와 크로스 브라우저 호환성을 위해 열기 전에 지정하는 것이 좋습니다.

3.3.readystatechange 이벤트에서 먼저 응답이 수신되었는지 확인한 다음, xhr.status가 2로 시작하는 상태 코드가 성공임을 의미합니다. Obtain, 위의 코드는 각 요청에 임의의 숫자를 추가하므로 값이 캐시에서 검색되지 않으므로 이 상태를 판단할 필요가 없습니다.

4. Ajax 요청은 도메인을 넘을 수 없습니다!

2. JSONP

 JSONP(JSON with Padding)는 도메인 간 요청 방법입니다. 주요 원칙은 스크립트 태그의 도메인 간 요청 기능을 활용하고 src 속성을 통해 서버에 요청을 보내고, 서버는 js 코드를 반환하고, 웹 페이지는 응답을 수락한 다음 직접 실행하는 것입니다. 이는 스크립트 태그를 통해 외부 파일을 참조하는 원리와 동일합니다.

JSONP는 콜백 함수와 데이터 두 부분으로 구성됩니다. 콜백 함수는 일반적으로 웹 페이지에 의해 제어되며 서버는 함수와 데이터를 문자열로 결합하여 반환합니다.

예를 들어 웹 페이지는 스크립트 태그를 생성하고 해당 src 값을 http://www.superfiresun.com/json/?callback=process에 할당합니다. 이때 웹 페이지는 요청을 시작합니다. 서버는 반환할 데이터를 모아 함수의 매개변수로 전달합니다. 서버가 반환하는 데이터 형식은 "process({'name':'superfiresun'})"와 유사합니다. 요청자가 스크립트이기 때문에 응답 값은 프로세스 메서드를 직접 호출하고 매개변수를 전달하는 것과 동일합니다.

응답으로 반환된 데이터를 보면 JSONP에는 ajax 메서드보다 콜백 함수가 하나 더 있습니다.

 function jsonp(options) {
        options = options || {};
        if (!options.url || !options.callback) {
            throw new Error("参数不合法");
        }

        //创建 script 标签并加入到页面中
        var callbackName = (&#39;jsonp_&#39; + Math.random()).replace(".", "");
        var oHead = document.getElementsByTagName(&#39;head&#39;)[0];
        options.data[options.callback] = callbackName;
        var params = formatParams(options.data);
        var oS = document.createElement(&#39;script&#39;);
        oHead.appendChild(oS);

        //创建jsonp回调函数
        window[callbackName] = function (json) {
            oHead.removeChild(oS);
            clearTimeout(oS.timer);
            window[callbackName] = null;
            options.success && options.success(json);
        };

        //发送请求
        oS.src = options.url + &#39;?&#39; + params;

        //超时处理
        if (options.time) {
            oS.timer = setTimeout(function () {
                window[callbackName] = null;
                oHead.removeChild(oS);
                options.fail && options.fail({ message: "超时" });
            }, time);
        }
    };

    //格式化参数
    function formatParams(data) {
        var arr = [];
        for (var name in data) {
            arr.push(encodeURIComponent(name) + &#39;=&#39; + encodeURIComponent(data[i]));
        }
        return arr.join(&#39;&&#39;);
    }

1、因为 script 标签的 src 属性只在第一次设置的时候起作用,导致 script 标签没法重用,所以每次完成操作之后要移除;

2、JSONP这种请求方式中,参数依旧需要编码;

3、如果不设置超时,就无法得知此次请求是成功还是失败;

三、模仿JQuery中的ready()事件

1、DOMContentLoaded事件,在DOM树加载完成之后立即执行,始终会在load之前执行。
    IE9+、FF、Chrome、Safari3.1+和Opera9+都支持该事件。

    对于不支持该事件的浏览器,可以使用如下代码:

setTimeout(function(){
  // 代码块}, 0) ;

    DOMContentLoaded 事件只能通过 DOM2 级方式添加,即采用addEventListener()/attachEvent() 方式添加才能够使用。事件对象不会提供任何额外信息。

2、readystatechange事件

    IE为DOM文档中的某些部分(区别于 XHR 对象的 readystatechange 事件)提供了该事件,这个事件的目的是提供与文档或元素的加载状态有关的信息,但这个事件的行为有时候也很难预料。支持该事件的对象都有一个readyState属性,注意,不是 event 事件对象。IE、Firefox4+和Opera 支持该事件。

readyState属性的值如下:
    “uninitialized” - 未初始化:对象存在但尚未初始化;
    “loading” - 正在加载:对象正在加载数据;
    “loaded” - 加载完毕,对象加载数据完毕;
    “interactive” - 交互:可以操作对象了,但还没有完全加载;
    “complete” - 完成:对象已经加载完成;

2.1、并非所有的对象都会经历readyState的这几个阶段,如果这个阶段不适用某个对象,则该对象完全可能跳过该阶段,并没有规定哪个阶段适用于哪个对象。这意味着 readystatechange 事件经常会少于4次,相对应的 readyState 属性值也不是连续的。

 

2.2、对于 document 而言,interactive 和 complete 阶段会在于 DOMContentLoaded 大致相同的时刻触发 readystatechange 事件;

  load 事件和 readystatechange 事件的触发顺序会因页面的外部资源的多少而变化,也就是说,readystatechange 事件并不会一直在 load 事件之前执行。外部资源越多,对 readystatechange 事件就越有利。

  interactive 和 complete 的顺序也是不一致的,谁都有可能先执行,引用的外部资源越多,对交互阶段越有利。所以为了尽可能早的执行代码,两个状态要同时判断。

3、doScroll 
IE5.5+支持,当页面中有滚动条时,可以用 doScroll("right")/doScroll("down") 等来移动滚动条,这个方法只有等DOM加载完成以后才能用,所以在IE低版本浏览器中可以通过这个属性判断 DOM 结构是否加载完成。介绍这个属性主要是模仿 jquery 中的解决方案。

function ready(readyFn) {
        //非IE浏览器
        if (document.addEventListener) {
            document.addEventListener(&#39;DOMContentLoaded&#39;, function () {
                readyFn && readyFn();
            }, false);
        } else {
            //方案1和2  哪个快用哪一个
            var bReady = false;
            //方案1
            document.attachEvent(&#39;onreadystatechange&#39;, function () {
                if (bReady) {
                    return;
                }
                if (document.readyState == &#39;complete&#39; || document.readyState == "interactive") {
                    bReady = true;
                    readyFn && readyFn();
                };
            });

            //方案2
            //jquery也会担心doScroll会在iframe内失效,此处是判断当前页是否被放在了iframe里
            if (!window.frameElement) {
                setTimeout(checkDoScroll, 1);
            }
            function checkDoScroll() {
                try {
                    document.documentElement.doScroll("left");
                    if (bReady) {
                        return;
                    }
                    bReady = true;
                    readyFn && readyFn();
                }
                catch (e) {
                    // 不断检查 doScroll 是否可用 - DOM结构是否加载完成
                    setTimeout(checkDoScroll, 1);
                }
            };
        }
    };

注:
setTimeout(checkDoScroll, 1); 目的是让浏览器尽快执行 checkDoScroll 函数,间隔时间设置为 1ms,对当下的浏览器来说是不太可能的。每个浏览器都有自己默认的最小间隔时间,即使时间设置为最小间隔时间,也只是代表隔这些时间过去之后,JavaScript 会把 checkDoScroll 加入到执行队列中,如果此时 JavaScript 进程空闲,则会立即执行该代码。


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.