1、关键点
dispatchRequest中主要做了两件事,
先通过transformData对请求数据进行处理,然后定义适配器adapter并执行,
通过 .then 方法 对adapter(适配器)
resolve 出的响应数据进行处理(transformData)并返回 response,
失败返回一个状态为rejected`的 Promise 对象。
到此,当用户调用 axios()时,可以链式调用 Promise 的 .then() 和 .catch() 来处理业务逻辑了。
2、使用
生成promise链:
let chain = [请求拦截x, ..., 请求拦截2,请求拦截1, dispatchRequest, undefined, 响应拦截1,响应拦截2, ...响应拦截x]
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
3、源码
lib/core/dispatchRequest.js
// 1、adapter:适配器,包含浏览器端 xhr 和 node 端的 http
let transformData = require('./transformData')
var defaults = require('../../defaults');
module.exports = function dispatchRequest(config) {
// config 是所有请求拦截后的config(因为config可能在拦截时被改动)
// ...transformData 转换请求数据类型
// 适配器,可自定义,没有的用默认的
const adapter = config.adapter || defaults.adapter
// 通过适配器处理 config 配置,返回服务端响应数据 response
return adapter(config).then(function onAdapterResolution(response) {
// ...转换响应数据
return response
}, function onAdapterRejection(reason) {
//...
return Promise.reject(reason)
})
}
axios.js
Axios.prototype.request = function request(config) {
// 为了支持 request(url, {...}), request({url, ...})
// 方式二:axios('https://xxxx') ,判断参数字符串,则赋值给 config.url
if (typeof config === 'string') {
config = arguments[1] || {};
config.url = arguments[0];
} else {
// 方式一:axios({}) ,参数为对象,则直接赋值给 config
config = config || {};
}
// 配置优先级: 调用方法的配置 > 实例化axios的配置 > 默认配置
// 举个例子,类似:axios.get(url, {}) > axios.create(url, {}) > 内部默认设置
config = mergeConfig(this.defaults, config);
// 生成请求拦截队列
var requestInterceptorChain = [];
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
});
// 生成响应拦截队列
var responseInterceptorChain = [];
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
});
/*
创建用于保存请求/响应拦截函数的数组
数组的中间放发送请求的函数
数组的左边放请求拦截器函数(成功/失败)
数组的右边放响应拦截器函数
undefined为啥? --> 因为拦截器是成对存在的,所以此处用undefined占位,后续在promise链中可以同前面的一对一对拿出移除
*/
// 编排整个请求的任务队列
// 派发请求 dispatchRequest 看下篇
var chain = [dispatchRequest, undefined];
// 为什么unshift要用Array.prototype.unshift.apply??
Array.prototype.unshift.apply(chain, requestInterceptorChain);
chain.concat(responseInterceptorChain);
var promise;
// 传入配置
promise = Promise.resolve(config);
// 形成 promise 链条调用
// 循环 chain ,不断从 chain 中取出设置的任务,通过 Promise 调用链执行 , 一对一对拿出,一个成功一个失败处理
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
// ...
return promise;
};
默认的defaults
import utils from './utils'
var defaults = {
// ...
// 请求超时时间,默认不超时
timeout: 0,
// ...转换请求数据
// ...转换响应数据
// ...判断响应状态码的合法性: [200, 299]
adapter: getDefaultAdapter()
}
function getDefaultAdapter () {
var adapter;
// 判断当前环境,然后去请求
if (typeof XMLHttpRequest !== 'undefined') {
// 浏览器
adapter = require('./adapters/xhr')
} else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
// NODE环境,使用http模块
adapter = require('./adapters/http')
}
return adapter
}