Quote: Axios is often used in projects, but I was asked to wrap Ajax in AXIos form in an interview, which I didn’t write down. It seems that still can not stay on the surface of use. It is not difficult to come back to study promise. The key is to master promise A+ specification and promise writing. Let’s see how Axios implements this.

Axios source code:

I, Axios, am a Promise based HTTP client for the browser and Node.js.

Let’s focus on the Ajax section I want to learn about.

Adapters module in AXIOS

The modules under adapters/ are modules that handle dispatching a request and settling a returned Promise once a response is received. This module mainly handles distribution requests and processes them once a response to a returned Promise has been received.

In the source view: axios/lib/adapters/XHR. Js one let me shine at the moment:

module.exports = function xhrAdapter(config) {
 return new Promise(function dispatchXhrRequest(resolve, reject) {})}Copy the code

We found the Promise base! Open, onReadyStatechange, send, etc.

  / / = >... omit config...
  // step1=>
  var request = new XMLHttpRequest();
  // step2=>
  request.open(config.method.toUpperCase(), buildURL(config.url, config.params, config.paramsSerializer), true);
  // step3=>
  request.onreadystatechange = function handleLoad() {
    if(! request || request.readyState ! = =4) {
      return;
    }
  
    // The request errored out and we didn't get a response, this will be
    // handled by onerror instead
    // With one exception: request that using file: protocol, most browsers
    // will return status as 0 even though it's a successful request
    if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') = = =0)) {
      return;
    }
  
    // Prepare the response
    var responseHeaders = 'getAllResponseHeaders' in request ? parseHeaders(request.getAllResponseHeaders()) : null;
    varresponseData = ! config.responseType || config.responseType ==='text' ? request.responseText : request.response;
    var response = {
      data: responseData,
      status: request.status,
      statusText: request.statusText,
      headers: responseHeaders,
      config: config,
      request: request
    };
  
    settle(resolve, reject, response);
    // Clean up request
    request = null;
  };
  / / = >... omit handle process...
  // step4=>
  request.send(requestData);
Copy the code

This is just an ajax implementation, but the core then chain call is not implemented. The real implementation is to use axios/lib/core/settle.

/**
* Resolve or reject a Promise based on response status.
*
* @param {Function} resolve A function that resolves the promise.
* @param {Function} reject A function that rejects the promise.
* @param {object} response The response.
*/
module.exports = function settle(resolve, reject, response) {
 var validateStatus = response.config.validateStatus;
 if(! validateStatus || validateStatus(response.status)) { resolve(response); }else {
   reject(createError(
     'Request failed with status code ' + response.status,
     response.config,
     null, response.request, response )); }};Copy the code

Once critical resolve and Reject are resolved, follow the Promise A+ specification

A promise must provide then methods to access its current or final value or cause.

Then (onFulfilled, onRejected), two of the methods can be used to process the return. The above has basically implemented ajax functions.

Following axios’s lead, encapsulate your own promise_Ajax

Initial implementation of your own P_ajax

function pajax({
    url= null,
	method = 'GET',
	dataType = 'JSON',
	async = true}){
	return new Promise((resolve, reject) = > {
		let xhr = new XMLHttpRequest()
		xhr.open(method, url, async)
		xhr.responseType = dataType
		xhr.onreadystatechange = (a)= > {
			if(!/^[23]\d{2}$/.test(xhr.status)) return
			if(xhr.readyState === 4) {
				let result = xhr.responseText
				resolve(result)
			}
		}
		xhr.onerror = (err) = > {
			reject(err)
		}
		xhr.send()
	})
}
Copy the code

JSON format is called by default and the test succeeds

ajax({
    url:'./test.json'.method: 'get'
}).then((result) = >{
    console.log(result)
},(err)=>{

})
Copy the code

Upgrade to optimize

For different request types, file types, do different processing

  • Cache false indicates that the cache is not set. The simplest solution is to add _*** to the cache. *** is a random number
// Check whether the request type is GET
let isGet = /^(GET|DELETE|HEAD)$/i.test(method)
// Check whether the url exists. , add & if there is
let symbol = url.indexOf('? ') >- 1 ? '&' : '? '
// GET requests are processed in the cache
if(isGet){ ! cache ? url+=`${symbol}_The ${Math.random()}`: null
}
Copy the code
  • Result is treated differently depending on the return type
    let result = xhr.responseText
    // Process the returned content according to dataType, i.e., different file types
    switch(this.dataType.toUpperCase()){
        case 'TEXT':
        case 'HTML':
            break;
        case 'JSON':
            result = JSON.parse(result)
            break;
        case 'XML':
            result = xhr.responseXML
    }   
Copy the code
  • When data is an object, it is converted to STR, and the aspect GET requests passing parameters
   function formatData(data){
       if(Object.prototype.toString.call(data)==='[object Object]') {let obj = data
           let str = ' '
           for(let key in obj){
               if(obj.hasOwnProperty(key)){
                   str+=`${key}=${obj[key]}& `}}// Remove the extra & at the end
           str = str.replace(/&$/g.' ')
           return str
       }
   }
   if(data ! = =null){
       data = formatData(data)
       if(isGet){
           url += symbol + data
           data = null}}Copy the code

Simple test results:

pajax({
        url:'./test.json'.method: 'get'.cache: false.data: {name:'jyn'.age:20
        }
	}).then((result) = >{
	    console.log(result)
    },(err)=>{
        console.log(err)
    })
Copy the code

The operation result is: the Request URL: http://localhost:63342/june/HTTP_AJAX/test.json? _0. 6717612341262227? Name =jyn&age=20, and then method can also get file data. When cache is set to false, the cache is refreshed every time and the cache is retrieved 200.

And there you have it, simple Ajax based on Promise!

Author: Yanni Jia Nickname: rabbit very much Reference: axios source: https://github.com/axios/axios