本文只关注axios源码之取消请求这个知识点的实现,如想看完整源码解析,请移步若川大佬的axios源码解析, axios是基于promise封装的,看axios需先对promise有所了解
取消请求的使用
const CancelToken = axios.CancelToken; const source = CancelToken.source(); var options = { url: 'xxxx', data: {}, method: 'post', cancelToken: source.token }; axios(options).then(function (res) {}) // 调用cancel取消请求 source.cancel('请求取消了');
如上:调用source.cancel便可取消请求
疑问:为什么source.cancel可以取消请求?源码关于取消请求的实现
先看 axios\lib\adapters\xhr.js 里面是什么时候取消请求的,源码如下:
if (config.cancelToken) { // Handle cancellation config.cancelToken.promise.then(function onCanceled(cancel) { if (!request) { return; } // 取消请求 request.abort(); reject(cancel); // Clean up request request = null; }); }
可看出在config.cancelToken.promise.then里面取消的
疑问:config.cancelToken.promise.then什么时候调的,为什么source.cancel可以触发then的执行?取消请求实现
看源码之前。先看一个小例子:let t = new Promise((resolve) => { resolve('执行') }) t.then(res => { console.log(res) })
这里只要执行t.then, '执行'就被打印了,如果我想想在任何需要的地方去执行resolve('执行'),只能同过setTimeout去执行t.then, 但是在axios源码里面config.cancelToken.promise.then的调用时间已经定死了,我们只能通过source.cancel去控制config.cancelToken.promise.then的执行
改造上方代码:
let t = new Promise((resolve) => { // 把resolve引用存起来,需要执行的时候再执行 delayedResolve = resolve }) t.then(res => { console.log(res) }) setTimeout(() => { delayedResolve('需要执行的时候在执行') }, 3000)
可以看到,我们可以灵活控制delayedResolve的调用时间来触发t.then的执行
上axios取消请求的源码:function CancelToken(executor) { if (typeof executor !== 'function') { throw new TypeError('executor must be a function.'); } var resolvePromise; this.promise = new Promise(function promiseExecutor(resolve) { resolvePromise = resolve; }); var token = this; executor(function cancel(message) { if (token.reason) { // Cancellation has already been requested return; } token.reason = new Cancel(message); resolvePromise(token.reason); }); }
CancelToken.source = function source() { var cancel; var token = new CancelToken(function executor(c) { cancel = c; }); return { token: token, // 返回的一个构造函数 cancel: cancel }; };
分析:
cancel肯定是一个函数,CancelToken接收一个函数executor, executor再接收一个函数 cancel = function cancel(message),并将此函数复制给CancelToken.source.cancel,cancel 里面调用了CancelToken.promise的resolve。 由此可以通过任意时间调用source.cancel来触发CancelToken.promise的resolve
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。