看了下 axios 的源码,主要是 好奇 axios 中的 拦截器的实现与 取消发送的 机制
简单的实现了下,插个眼
拦截器
// 添加请求拦截器
axios.interceptors.request.use(function interceptorsBefore(config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function interceptorsAfter(response) {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
return response;
}, function (error) {
// 超出 2xx 范围的状态码都会触发该函数。
// 对响应错误做点什么
return Promise.reject(error);
});
拦截器主要分为 请求拦截器 和 响应拦截器
在 源码的 Axios 文件下 request方法 62 行
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);
});
var promise;
// dispatchRequest 是主要的 发送请求的方法
var chain = [dispatchRequest, undefined];
/*
*
*/
// 利用数组的Apply 方法传递数组的方法,把 请求拦截器数组插入到 chain 头部
Array.prototype.unshift.apply(chain, requestInterceptorChain);
// 把 响应拦截器数组插入到 chain 头部
chain = chain.concat(responseInterceptorChain);
现在 chain 变成了
chain = [请求拦截成功,请求拦截失败,发送请求,undefined, 响应拦截成功,响应拦截失败]
现在开始执行,依旧在 request 方法里
var promise = Promise.resolve(config);
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
return promise;
到达用户手中,只剩下一个 由最后一个响应拦截处理过后的 Promise
自己简单实现
由于axios 实例需要 axios.interceptors.request 这种写法
const myAxios = function () {
this.interceptors = {
request: new Interceptors,
response: new Interceptors,
}
}
function Interceptors() {
this.handlers = []
}
Interceptors.prototype.use = function (fulfiled, rejected = () => { }) {
this.handlers.push(
fulfiled,
rejected
)
}
重点: 生成自己的 Promise Chain dispathRequest 模拟真正请求的方法
myAxios.prototype.request = function (config) {
let p = Promise.resolve(config)
let chain = [dispathRequest, undefined]
Array.prototype.unshift.apply(chain, this.interceptors.request.handlers)
Array.prototype.push.apply(chain, this.interceptors.response.handlers)
while (chain.length) {
p = p.then(chain.shift(), chain.shift())
}
return p
}
//
function dispathRequest(config) {
return new Promise((resolve, reject) => {
resolve(config)
})
}
使用 拦截器
let m = new myAxios
m.interceptors.request.use(function success1(config) {
console.log("successRequest");
return config
}, function error1(err) {
return err
})
m.interceptors.response.use(function success2(config) {
console.log("successResponse");
return config
}, function error2(err) {
console.log("error");
return err
})
发送请求
let obj = { a: 20 }
m.request( obj ).then(res => {
console.log(res, "res");
})
obj 会随着 request 到达,请求拦截器,请求拦截器 return config
Promise 的机制就是上一个 then 中如果返回的 是个普通值(非Promise)类型,这个 返回的值就会被当做 下一个 then 的 value 值,如果是 Promise 类型,会解析 这哥 Pormise
dispathRequest 得到这个 config,继续执行, 响应拦截器 获取 数据
执行完毕,request最后 返回一个 promise
m.request({ a: 20 }).then(res => {
console.log(res, "res");
})
取消请求
const CancelToken = axios.CancelToken;
let cancel;
axios.get('/user/12345', { cancelToken: new CancelToken(function executor(c) {
// executor 函数接收一个 cancel 函数作为参数
cancel = c;
})
});
// 取消请求
cancel();
原理是巧妙的 Promise 的resolve 可以更改 Promise 状态 生成 cancelToken
let cancel;
function CancelToken(excutor) {
let resolvePromise;
this.promise = new Promise((resolve, reject) => {
resolvePromise = resolve
})
excutor(function () {
resolvePromise("cancelToken")
})
}
let cancelToken = new CancelToken(function (c) {
cancel = c
})
首先生成 CancelToken 函数,传入 excutor(执行器),同时把 resolve 赋值给 外部变量 resolvePromise,这样的话,this.promise 的状态时 pending,把控制权 交给了 resolvePromise
也就是 下个函数中的 function (c){}
excutor(执行器) 中的 function () {resolvePromise("cancelToken")} 传递 参数 给 c,也就是说,现在 cancel 一旦执行,excutor中的 就会执行,resolvePromise 就会执行,this.promise 的状态就会发生改变
把 cancel 给axios 实例带上
m.request({ a: 20, cancelToken: cancel }).then(res => {
console.log(res, "res");
})
function dispathRequest(config) {
return new Promise((resolve, reject) => {
if (config.cancelToken) {
config.cancelToken()
reject("取消请求")
}
resolve(config)
})
}
cancelToken.promise.then(res => {
console.log(res);
}).catch(err => {
console.log(err);
})
全部代码 个人感觉还是很巧妙的
const myAxios = function () {
this.interceptors = {
request: new Interceptors,
response: new Interceptors,
}
}
myAxios.prototype.request = function (config) {
let p = Promise.resolve(config)
let chain = [dispathRequest, undefined]
Array.prototype.unshift.apply(chain, this.interceptors.request.handlers)
Array.prototype.push.apply(chain, this.interceptors.response.handlers)
while (chain.length) {
p = p.then(chain.shift(), chain.shift())
}
return p
}
function dispathRequest(config) {
return new Promise((resolve, reject) => {
if (config.cancelToken) {
config.cancelToken()
reject("取消请求")
}
resolve(config)
})
}
function Interceptors() {
this.handlers = []
}
Interceptors.prototype.use = function (fulfiled, rejected = () => { }) {
this.handlers.push(
fulfiled,
rejected
)
}
let m = new myAxios
m.interceptors.request.use(function success1(config) {
console.log("successRequest");
return config
}, function error1(err) {
return err
})
m.interceptors.response.use(function success2(config) {
console.log("successResponse");
return config
}, function error2(err) {
console.log("error");
return err
})
let cancel;
function CancelToken(excutor) {
let resolvePromise;
this.promise = new Promise((resolve, reject) => {
resolvePromise = resolve
})
excutor(function () {
resolvePromise("cancelToken")
})
}
let cancelToken = new CancelToken(function (c) {
cancel = c
})
cancelToken.promise.then(res => {
console.log(res);
}).catch(err => {
console.log(err);
})
m.request({ a: 20, cancelToken: cancel }).then(res => {
console.log(res, "res");
})
note:time:2022/7/11