初识Axios源码

//暗号:axios

处理异步在处理前后端的业务时的考虑问题,前端的Ajax = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)就是处理异步的问题,随后Fetch和Axios进一步封装了Ajax,使得接口更加丰富。

1. Axios的创建

axios({
  url,
  method,
  headers,
})

axios(url, {
  method,
  headers,
})

axios.get(url, {
  headers,
})

axios.post(url, data, {
  headers,
})
axios.create(optios)

axios创建方法方法: 1. axios() -- axios方法创建, 2. axios.create()对象的create方法创建, 3.axios.request()

// Axios引入 (axios/index.js)
module.exports = require(‘./lib/axios‘)

 

axios/lib/axios.js中的createInstance能够实现axios的多种创建方式

function createInstance(defaultConfig) {

 // 创建一个Axios的实例但是最终返回的并不是这个实例
var context = new Axios(defaultConfig);

 // 创建一个instance的容器,指向Axios.prototyep.request方法,并上下文指向context,最终返回。 
 // 我们能用Axios() => instance()
var instance = bind(Axios.prototype.request, context);  // 把Axios.prototype上的方法扩展到instance对象上。
 // 这样instance又有了get、post、put等方法
 // 并指向上下文context,这样执行Axios原型链上的方法时,this会指向context utils.extend(instance, Axios.prototype, context); // 把context对象上的自身属性和方法扩展到instance上
 // extend方法会遍历对象本身,不会表里原型链上的方法和属性
// instance就有了create,default, interceptors的方法和属性
utils.extend(instance, context); return instance; } // 调用axios()方法时候,使用默认配置 var axios = createInstance(defaults); // Expose Axios class to allow class inheritance axios.Axios = Axios; // Factory for creating new instances
// 合并配置项
axios.create = function create(instanceConfig) { return createInstance(mergeConfig(axios.defaults, instanceConfig)); };

 

Axios模块是axios的核心,一个Axios实例对应一个axios对象,其他方法都是对Axios内容的扩展
Axios构造函数的核心方法是request方法,各种axios的调用方式最终都是通过request方法发请求的。
调用axios等同于Axios.prototype.request
调用axios.reuqest等同于Axios.prototype.request
调用axios.get等同于Axios.ptototype.get
// /lib/core/Axios.js

function Axios(instanceConfig) { this.defaults = instanceConfig; this.interceptors = { request: new InterceptorManager(), response: new InterceptorManager() }; } Axios.prototype.request = function request(config) { // ...处理配置和参数合并处理,省略代码 }; // 为支持的请求方法提供别名 utils.forEach([‘delete‘, ‘get‘, ‘head‘, ‘options‘], function forEachMethodNoData(method) { Axios.prototype[method] = function(url, config) { return this.request(utils.merge(config || {}, { method: method, url: url })); }; }); utils.forEach([‘post‘, ‘put‘, ‘patch‘], function forEachMethodWithData(method) { Axios.prototype[method] = function(url, data, config) { return this.request(utils.merge(config || {}, { method: method, url: url, data: data })); }; });

 

2. 统一发送请求的适配器adapter

adapter是xhr.js封装的promise对象, 它统一了不同环境发送请求的需求。 
// default.js
// 适配器
var
adapter = config.adapter || defaults.adapter; return adapter(config).then(function onAdapterResolution(response) { throwIfCancellationRequested(config); // 处理不同环境发出的request请求 function getDefaultAdapter() { var adapter; if (typeof XMLHttpRequest !== ‘undefined‘) { // 处理浏览器的发出的请求 adapter = require(‘./adapters/xhr‘);
}
else if (typeof process !== ‘undefined‘ && Object.prototype.toString.call(process) === ‘[object process]‘) { // For node use HTTP adapter // 处理node环境的发出的请求 adapter = require(‘./adapters/http‘); } return adapter; }

 

// xhr.js

// 返回xhr的promise对象

module.exports = function xhrAdapter(config) {
  return new Promise(function dispatchXhrRequest(resolve, reject) {
 
    var request = new XMLHttpRequest();

    // Send the request
    request.send(requestData);
  });
};

 

 

3. InterceptoManager 拦截器

Axios.js中有一个拦截器InterceptorManager, 可以简单理解为一个request或者response的数组,每次从队列头部或者尾部传入request或者response的promise对象fullfilled和rejected函数
// InterceptorManager.js
// InterceptorManager方法维护一个数组
function InterceptorManager() {
  this.handlers = [];
}

// 每次在数组尾部加入promise对象, use方法进行注册
InterceptorManager.prototype.use = function use(fulfilled, rejected) {
  this.handlers.push({
    fulfilled: fulfilled,
    rejected: rejected
  });
  return this.handlers.length - 1;
};

 

4. 执行链处理拦截器的请求和响应

处理ajax的promise请求前,执行链chain会把拦截器数组中的promise对象请求unshift和响应push加入chain数组中, 

  // 创建一个执行链 [dispatchRequest, undefined], dispatchRequest是适配器ajax中封装的promise请求
  var chain = [dispatchRequest, undefined];
  var promise = Promise.resolve(config);

  this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
    chain.unshift(interceptor.fulfilled, interceptor.rejected);
  });

  this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
    chain.push(interceptor.fulfilled, interceptor.rejected);
  });

 // 执行顺序promise.then(rs2, rf2).then(rs1, rf1). then(dispatchRequest, undefine).then(ps1, pf1).then(ps2, pf2)...
while (chain.length) { promise = promise.then(chain.shift(), chain.shift()); } return promise; };

 

5.  执行链处理请求和响应的promise对象的顺序

    数组的 shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。
    每次执行while循环,从chain数组里按序取出两项,并分别作为promise.then方法的第一个和第二个参数

    按照我们使用InterceptorManager.prototype.use添加拦截器的规则,正好每次添加的就是我们通过InterceptorManager.prototype.use方法添加的成功和失败回调

    通过InterceptorManager.prototype.use往拦截器数组里添加拦截器时使用的数组的push方法,
    对于请求拦截器,从拦截器数组按序读到后是通过unshift方法往chain数组数里添加的,又通过shift方法从chain数组里取出的,所以得出结论:对于请求拦截器,先添加的拦截器会后执行
    对于响应拦截器,从拦截器数组按序读到后是通过push方法往chain数组里添加的,又通过shift方法从chain数组里取出的,所以得出结论:对于响应拦截器,添加的拦截器先执行

    第一个请求拦截器的fulfilled函数会接收到promise对象初始化时传入的config对象,而请求拦截器又规定用户写的fulfilled函数必须返回一个config对象,所以通过promise实现链式调用时,每个请求拦截器的fulfilled函数都会接收到一个config对象

    第一个响应拦截器的fulfilled函数会接受到dispatchRequest(也就是我们的请求方法)请求到的数据(也就是response对象),而响应拦截器又规定用户写的fulfilled函数必须返回一个response对象,所以通过promise实现链式调用时,每个响应拦截器的fulfilled函数都会接收到一个response对象

    任何一个拦截器的抛出的错误,都会被下一个拦截器的rejected函数收到,所以dispatchRequest抛出的错误才会被响应拦截器接收到。

    因为axios是通过promise实现的链式调用,所以我们可以在拦截器里进行异步操作,而拦截器的执行顺序还是会按照我们上面说的顺序执行,也就是 dispatchRequest 方法一定会等待所有的请求拦截器执行完后再开始执行,响应拦截器一定会等待 dispatchRequest 执行完后再开始执行。

 // 暗号:axios

初识Axios源码

上一篇:Python zip() 函数


下一篇:SpringMVC之RequestMapping执行过程(HandlerMapping篇)