axios cancelToken原理解析

46 min read

实例使用

const CancelToken = axios.CancelToken;
let cancel;

axios.get('/data', {
  cancelToken: new CancelToken(function executor(c) {
    // executor 函数接收一个 cancel 函数作为参数
    // 把cancel函数传递给外面,使得外面能控制执行取消请求
    cancel = c;
  })
});

// cancel the request
cancel();

从source 开始

CancelToken.source = function source() {
    var cancel;
    var token = new CancelToken(function executor(c) {
        // c 就是CancelToken中给executor传入的cancel方法
        cancel = c;
    });
    return {
        token: token,
        cancel: cancel
    };
};

module.exports = CancelToken;

CancelToken.source 返回一个对象

{
        token: token,
        cancel: cancel
};

token 是 CancelToken实例 , 用来区别不同对象

CancelToken 接受一个函数作为对象,将且赋值给外部进行调用,外部接受类似字符串这些提示信息, 传递到内部时经过一个回调函数cancel

而cancel 是内部来结束请求的方法,用来更新promise 状为fullfill

// axios/lib/cancel/CancelToken.js

'use strict';

var Cancel = require('./Cancel');

function CancelToken(executor) {
    if (typeof executor !== 'function') {
        throw new TypeError('executor must be a function.');
    }
    /**
    * 定义一个将来能执行取消请求的promise对象,当这个promise的状态为完成时(fullfilled),
    * 就会触发取消请求的操作(执行then函数)。而执行resolve就能将promise的状态置为完成状态。
    * 这里把resolve赋值给resolvePromise,就是为了在这个promise外能执行resolve而改变这个promise的状态
    * 注意这个promise对象被赋值给CancelToken实例的属性promise,将来定义then函数就是通过这个属性得到promise
    */
    var resolvePromise;
    this.promise = new Promise(function promiseExecutor(resolve) {
        resolvePromise = resolve;
    });
    /**
    * 将CancelToken实例赋值给token
    * 执行executor函数,将cancel方法传入executor,
    * cancel方法可调用resolvePromise方法,即触发取消请求的操作
    */
    var token = this;
    executor(function cancel(message) {
        if (token.reason) {
            // 取消已响应 返回 
            return;
        }
        token.reason = new Cancel(message);
        // 这里执行的就是promise的resolve方法,改变状态
        resolvePromise(token.reason);
  });
}

将 resolve 函数执行交给外部

var resolvePromise;
this.promise = new Promise(function promiseExecutor(resolve) {
    resolvePromise = resolve;
});

最终实现取消请求

config 对象是 axios 的请求配置对象

config.cancelToken.promise是通过源码的this.promise的得到,只要 cancel() 执行,就会走这个promise的reslove方法,调用浏览器原生提供的request.abort()方法,达到取消请求的目的

if (config.cancelToken) { // 如果配置了cancelToken属性
    // 当promise为完成态时,这个then函数执行,即执行取消请求
    config.cancelToken.promise.then(function onCanceled(cancel) {
        if (!request) {
            return;
        }
        // 取消ajax请求
        request.abort();
        reject(cancel);
        // Clean up request
        request = null;
    });
}