cancelToken 源码解析

567 阅读2分钟

小知识,大挑战!本文正在参与「程序员必备小知识」创作活动

由于之前项目中需要使用 cancelToken 来取消接口,所以研究了一下 cancelToken 怎么使用,并且对源码进行了一定了解。

cancelToken 的使用 -> 「传送门

在这里记录一下我的理解,希望也能对大家有些帮助。

axios/lib/cancel/cancelToken.js

// 一下是 cancelToken.js 的源码
// 为了内容不要太长,一些感觉不太重要的部分被我删除了
var Cancel = require('./Cancel');
function CancelToken(executor) {
  var resolvePromise;
  this.promise = new Promise(function promiseExecutor(resolve) {
    // 将 Promise 的 resolve 方法赋值给 resolvePromise
    // 这样 resolvePromise 方法就可以在外部控制当前这个 Promise 的状态
    // 在外部调用 resolvePromise 就可以将 当前的 Promise 的状态推到 fullfilled
    resolvePromise = resolve;
  });

  // 在传入的函数中调用 resolvePromise
  // 这样就把 resolvePromise( 控制 Promise 状态的方法 )的控制权传递到外部
  // 即在外部通过 new CancelToken 创建 CancelToken对象时可以通过传参,取得这个 Promise 对象的控制权
  var token = this;
  // token 指向当前创建的 CancelToken 对象
  executor(function cancel(message) {
    if (token.reason) {
      // Cancellation has already been requested
      return;
    }

    // Cancel 构造函数比较简单,就是给 Cancel 对象添加一个 message 属性
    // 用于在取消接口的时候有一个信息的输出
    token.reason = new Cancel(message);
    resolvePromise(token.reason);
  });
}

// CancelToken.source 方法会构建一个 CancelToken 对象,并返回一个有两个参数的对象( token、cancel )
// token -> 指向构建出的 CancelToken 对象
// cancel -> 取消请求需要调用的方法
CancelToken.source = function source() {
  var cancel;
  var token = new CancelToken(function executor(c) {
    cancel = c;
  });
  return {
    token: token,
    cancel: cancel
  };
};

module.exports = CancelToken;

axios/lib/adapters/http.js

在 http.js 中关于 CancelToken 的内容只有下面一小段

if (config.cancelToken) {
    // 先校验了 cancelToken
    // 定义了 promise.then,即当 promise 的状态转变为 fullfilled 时执行的内容
    config.cancelToken.promise.then(function onCanceled(cancel) {
    if (req.aborted) return;
        req.abort();
        reject(cancel);
    });
}

个人理解

其实 CancelToken 的内容还是比较简单的,核心还是将 promise 的控制权通过参数的形式传递到外部,是使用者可以独立控制 promise 的状态,进而去控制接口;

// 小demo
let promiseFun = null
function promiseBtn() {
  let promise = new Promise((resolve) => {
    promiseFun = resolve;
  });
  promise.then((txt) => {
    alert(txt)
  })
  console.log(promise)

  setTimeout(() => {
    promiseFun('取消');
  }, 3000);
},