书接上回,上次说到 mergeConfig,这次是 this.request
request
以
axios.get("xx",params: { ID: 12345 })
/**
* Dispatch a request
*
* @param {String|Object} configOrUrl The config specific for this request (merged with this.defaults)
* @param {?Object} config
*/
Axios.prototype.request = function request(configOrUrl, config){
if (typeof configOrUrl === 'string') {
config = config || {};
config.url = configOrUrl;
} else {
config = configOrUrl || {};
}
// 合并配置项
config = mergeConfig(this.defaults, config);
// 由于 Axios 的 内部方法 中 使用 了
// this.interceptors = {
// request: new InterceptorManager_1(),
// }
// this.interceptors.request 是 拦截器 的实例,可以使用原型的方法,这种写法可以做到更好的分离
// 重点 是拦截器
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);
});
// 出现了一个 chain,其中的 dispatchRequest 是核心方法
var promise
var chain = [dispatchRequest, undefined];
//把 requestInterceptorChain unshift
// 由于 chain 是个数组,直接 unshift 有问题,利用 apply方法
Array.prototype.unshift.apply(chain, requestInterceptorChain);
chain = chain.concat(responseInterceptorChain);
// 这里的config 很重要,是作为promise 的实参,
promise = Promise.resolve(config);
//requestInterceptorChain 是 一个对象数组,
// 对象的第一项是 fullfilled函数,第二项是 rejected函数
// {fullfilled:function(config){return config },reject:fn}
//他们的这些函数config的就是从这里来的,修改了config
// 一定要return,以便后续能够拿到
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
return promise;
//
}
拦截器解析
// 当用户 不断的 `use` 添加 拦截器的时候
// 比如是用请求拦截器, 请求拦截器 实例会一直 push,最终形成
this.handler = [
{
fullfilled:function(config){return config },
rejected:fn
},{
fullfilled:fn,
rejected:undefined
}
]
当使用 `this.interceptors.request.forEach` 的时候
unshiftRequestInterceptors 中的形参(interceptor) =
({
fullfilled:function(config){ return config },
rejected:fn
})
requestInterceptorChain.unshift({ fullfilled:function(config){return config },rejected:fn })
this.defaults
var defaults = {
transitional: transitional,
adapter: getDefaultAdapter(),
timeout: 0,
validateStatus: function validateStatus(status) {
return status >= 200 && status < 300;
},
....
}
var defaults_1 = defaults;
function Axios(instanceConfig) {
this.defaults = instanceConfig;
this.interceptors = {
request: new InterceptorManager_1(),
response: new InterceptorManager_1()
};
}
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
return config;
}, function (error) {
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 2xx 范围内的状态码都会触发该函数。
return response;
}, function (error) {
// 超出 2xx 范围的状态码都会触发该函数。
return Promise.reject(error);
});
function InterceptorManager() {
this.handlers = [];
}
// 不断的 push
InterceptorManager.prototype.use = function use(fulfilled, rejected, options) {
this.handlers.push({
fulfilled: fulfilled,
rejected: rejected,
synchronous: options ? options.synchronous : false,
runWhen: options ? options.runWhen : null
});
return this.handlers.length - 1;
};
InterceptorManager.prototype.forEach = function forEach(fn) {
utils.forEach(this.handlers, function forEachHandler(h) {
if (h !== null) {
fn(h);
}
});
};
InterceptorManager.prototype.clear = function clear() {
if (this.handlers) {
this.handlers = [];
}
};
InterceptorManager.prototype.eject = function eject(id) {
if (this.handlers[id]) {
this.handlers[id] = null;
}
};
拦截器核心代码简化版
function InterceptorManager() {
this.handlers = [];
}
InterceptorManager.prototype.use = function use(fulfilled, rejected) {
this.handlers.push({
fulfilled: fulfilled,
rejected: rejected,
});
};
InterceptorManager.prototype.forEach = function forEach(fn) {
this.handlers.forEach(h => {
if (h !== null) {
fn(h);
}
})
};
function Bxios() {
this.defaultConfig = {
name: 'zs',
age: 20
}
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager()
};
}
function mid(res) {
return Promise.resolve({res,mid:"mid"})
}
Bxios.prototype.request = function (config) {
config = Object.assign(this.defaultConfig, config);
var before = [];
this.interceptors.request.forEach(function (interceptor) {
before.unshift(interceptor.fulfilled, interceptor.rejected);
})
var after = [];
this.interceptors.response.forEach(function (interceptor) {
after.push(interceptor.fulfilled, interceptor.rejected);
})
var chain = [mid, undefined];
Array.prototype.unshift.apply(chain, before);
chain = chain.concat(after);
promise = Promise.resolve(config);
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
return promise;
}
var a = new Bxios
a.interceptors.request.use(function (config) {
return {
...config,
xx: 'before'
}
})
a.interceptors.response.use(function (config) {
return {
...config,
after: 'after'
}
})
a.request().then(res=>{
console.log(res,"fininal")
})
Promise.resolve(1)
.then(res=>{return res+1})
.then(res=>{
console.log(res)
})
从拦截器的例子中可以看到对于数组的Array.prototype.unshift.apply(chain, requestInterceptorChain); 还是挺方便的,对于 this.request = { request: new InterceptorManager(), response: new InterceptorManager() }中的原型链的使用也需要学习,还有 promise的链式调用保证顺序也挺有意思
今天的拦截器就先写到这里 2022/9/29, 下一次写 dispatchRequest方法,还有一天国庆