Home  >  Article  >  Web Front-end  >  How to implement AJAX, JSONP and DOM loading completion events in native js

How to implement AJAX, JSONP and DOM loading completion events in native js

伊谢尔伦
伊谢尔伦Original
2016-11-21 14:47:42959browse

1. JS native Ajax

ajax: a way to request data without refreshing the entire page;
The technical core of ajax is the XMLHttpRequest object;
ajax request process: create an XMLHttpRequest object, connect to the server, send a request, and receive response data ;

The following simply encapsulates a function, which will be explained later

  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. Create

1.1, IE7 and above support native XHR objects, so you can use it directly: var oAjax = new XMLHttpRequest();

In 1.2, IE6 and previous versions, the XHR object is implemented through an ActiveX object in the MSXML library. Some books detail three different versions of such objects in IE, namely MSXML2. =new ActiveXObject ('Microsoft. Never used);

2.2. The GET request method submits data to the server through URL parameters, and POST submits the data to the server as send parameters;

2.3. In the POST request, before sending the data , to set the content type submitted by the form;

2.4. The parameters submitted to the server must be encoded through the encodeURIComponent() method. In fact, in the parameter list "key=value" form, both key and value need to be encoded, because Will contain special characters. Each time a request is made, a "v=xx" string will be spelled into the parameter list. This is to reject caching and request directly to the server every time.

encodeURI(): used to encode the entire URI. Special characters that belong to the URI will not be encoded, such as colons, forward slashes, question marks, and pound signs; its corresponding decoding function decodeURI();

encodeURIComponent() : Used to encode a certain part of the URI, and will encode any non-standard characters it finds; its corresponding decoding function decodeURIComponent();

3. Receiving


3.1. After receiving the response, the response data The XHR object will be automatically filled in, and the relevant attributes are as follows

responseText: the body content returned by the response, which is a string type;

responseXML: if the content type of the response is "text/xml" or "application/xml", this attribute will be saved The corresponding xml data is the document type corresponding to XML;

status: response HTTP status code;

statusText: description of HTTP status;

3.2. The readyState attribute of the XHR object represents the current active stage of the request/response process. This attribute The values ​​are as follows
0-not initialized, the open() method has not been called yet;
1-started, the open() method has been called, the send() method has not been called;

2-sent, the send() method has been called, and has not been received. response;

3-Receive, part of the response data has been received;
4-Complete, all response data has been received;

As long as the value of readyState changes, the readystatechange event will be called. (In fact, for logical smoothness, you can Put readystatechange after send, because when sending, requesting the server, network communication will take place, which takes time. It is also possible to specify the readystatechange event handler after send. I usually use it this way, but for the sake of standardization and cross-browser compatibility, it is still Specify it before opening).

3.3. In the readystatechange event, first determine whether the response is received, and then determine whether the server successfully processed the request. xhr.status is the status code. Status codes starting with 2 are successful. 304 means getting it from the cache. The above The code adds a random number to each request, so the value will not be retrieved from the cache, so there is no need to judge this status.

4. Ajax requests cannot cross domains!

2. JSONP

  JSONP (JSON with Padding) is a cross-domain request method. The main principle is to take advantage of the cross-domain request feature of the script tag, send the request to the server through its src attribute, the server returns the js code, the web page accepts the response, and then executes it directly. This is the same as the principle of referencing external files through the script tag. the same.

 JSONP consists of two parts: callback function and data. The callback function is generally controlled by the web page and sent to the server as a parameter. The server combines the function and data into a string and returns it.

 For example, the web page creates a script tag and assigns its src value to http://www.superfiresun.com/json/?callback=process. At this time, the web page initiates a request. The server puts together the data to be returned and passes it in as the parameters of the function. The format of the data returned by the server is similar to "process({'name':'superfiresun'})". The web page receives the response value because the requester is script. So it is equivalent to calling the process method directly and passing in a parameter.

 Looking at the data returned in the response, JSONP has one more callback function than the ajax method.

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

        //创建 script 标签并加入到页面中
        var callbackName = ('jsonp_' + Math.random()).replace(".", "");
        var oHead = document.getElementsByTagName('head')[0];
        options.data[options.callback] = callbackName;
        var params = formatParams(options.data);
        var oS = document.createElement('script');
        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 + '?' + 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) + '=' + encodeURIComponent(data[i]));
        }
        return arr.join('&');
    }

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('DOMContentLoaded', function () {
                readyFn && readyFn();
            }, false);
        } else {
            //方案1和2  哪个快用哪一个
            var bReady = false;
            //方案1
            document.attachEvent('onreadystatechange', function () {
                if (bReady) {
                    return;
                }
                if (document.readyState == 'complete' || 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 进程空闲,则会立即执行该代码。


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn