Process of parsing axios

The general idea is like this. ajax is encapsulated by promise's chain call, and the request result is returned to axios through the then method. The following is a step-by-step analysis. I hope you can point out the wrong places.

 

Prepare Axios constructor

Constructor is mainly used to store configuration information. default: it is used to store configuration information passed by axios (as shown in Figure 1). interceptors: intercept requests (as shown in Figure 2). get/post/request: send requests. All get/post here depend on the request method

function Ajax(){
    this.default = null;
    this.interceptors = {
        request: new InterceptorManger(),
        response: new InterceptorManger()
    }
}
Ajax.prototype.request = function(config){
    this.default = config;
}
Ajax.prototype.get = function(config){
    return Ajax.prototype.request(Object.assign({},{method:'get'},config));
}
Ajax.prototype.post = function(){
    return Ajax.prototype.request(Object.assign({},{method:'post'},config));
}

Prepare a createInstance function. The properties and methods of the function are the same as those of the Ajax instance

Someone here will ask, why prepare a createInstance function? Isn't it good to use Ajax instances directly? If so, it does not conform to the design concept of AXIOS source code. The author wants to send data through AXIOS functions instead of sending requests through AXIOS instances (as shown in Figure 3).

function createInstance(){
    var context = new Ajax();
    var instance = Ajax.prototype.request.bind(context);
    instance.CancelToken = CancelToken;
    Object.keys(context).forEach(function(key){
        instance[key] = context[key];
    })
    Object.keys(Ajax.prototype).forEach(function(key){
        instance[key] = Ajax.prototype[key];
    })
    console.dir(instance);
    return instance;
}
var axios = createInstance();

Build the request through the request function

The request axios obtains the requested data through then, so the return value of the request must be a promise object. First, a promise.resolve object needs to be built in the request function, and the configuration file is passed to then through resolve to execute and return ajax results. Here is a note: the return result of promise.then must be a promise object, which is the chain call of promise

Ajax.prototype.request = function(config){
    this.default = config;
    var promise = Promise.resolve(config);
    var chinas = [dispatchRequest,undefined];
    return promise.then(chinas[0],chinas[1]);
}
function dispatchRequest(config){
    return xhrAdapter(config).then(function(response){
        return response;
    },function(error){
        console.log(error);
    })
}
// Send ajax request
function xhrAdapter(options){
    return new Promise(function(resolve,reject){
        options = options || {};
        options.type = (options.type || "GET").toUpperCase();
        options.dataType = options.dataType || "json";
        var params = formatParams(options.data);
        if (window.XMLHttpRequest) {
            var xhr = new XMLHttpRequest();
        } else { //IE6 and below browsers
            var xhr = new ActiveXObject('Microsoft.XMLHTTP');
        }
        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);
            //Set the content type when the form is submitted
            xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            xhr.send(params);
        }
        xhr.onreadystatechange = function () {
            if (xhr.readyState == 4) {
                var status = xhr.status;
                if (status >= 200 && status < 300) {
                    resolve({
                        config: options,
                        data: xhr.response,
                        headers: xhr.getAllResponseHeaders(),
                        request: xhr,
                        status: status,
                        statusText: xhr.statusText
                    });
                } else {
                   reject(new Error("Request failed, request status code:"+status));
                }
            }
        }
        if(options.cancelToken){
            options.cancelToken.promise.then(function(){
                xhr.abort();
            })
        }
    })
}
//Format parameters
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("&");
}

Prepare InterceptorManger constructor to request interception

Now our main functions have been realized. Now we mainly complete some auxiliary functions, which is the characteristic part of axios. First of all, we need to understand that request interception is performed before sending the request, response interception is performed after sending the request, and some modifications need to be made in the request function, Store the callback function of request interception success / failure in the China array, and store the callback function of response interception success / failure in the China array before sending the request, and execute it successively after sending the request

Ajax.prototype.request = function(config){
    this.default = config;
    var promise = Promise.resolve(config);
    var chinas = [dispatchRequest,undefined];
    this.interceptors.request.handle.forEach(function(item){
        chinas.unshift(item.rejected);
        chinas.unshift(item.resolved);
    })
    this.interceptors.response.handle.forEach(function(item){
        chinas.push(item.resolved);
        chinas.push(item.rejected);
    })
    while(chinas.length>0){
        promise = promise.then(chinas.shift(),chinas.shift());
    }
    return promise;
}
function InterceptorManger(){
    this.handle = [];
}
InterceptorManger.prototype.use = function(resolved,rejected){
    this.handle.push({resolved,rejected})
}

Prepare the CancelToken constructor to cancel the request

Execute the cancel function through axios (as shown in Figure 4). The cancel function is the promise.resolve method instantiated by CancelToken. The execution of this method will call the promise.then method to cancel the request in ajax, which is equivalent to a process of subscribing to the publication and delaying the processing of the cancel function

function xhrAdapter(options){
    return new Promise(function(resolve,reject){
        ......
        if(options.cancelToken){
            options.cancelToken.promise.then(function(){
                xhr.abort();
            })
        }
    })
}
function CancelToken(executor){
    var resultResolve = null;
    this.promise = new Promise(function(resolve){
        resultResolve = resolve
    })
    executor(resultResolve);
}

Tags: Javascript Front-end Ajax

Posted on Thu, 28 Oct 2021 11:40:19 -0400 by mezise