axios源码分析之CancelToken

210 阅读1分钟

基本使用用法


// 方法1

cancelToken = this.$axios.CancelToken.source()

this.$axios.$get('api', {
  params,
  {},
  cancelToken: cancelToken.token
})
cancelToken.cancel('取消请求');


// 方法2
cancelToken = null

if (cancelToken) {
  cancelToken('取消请求')
  cancelToken = null
}

this.$axios.$get(url, {
  cancelToken: new this.$axios.CancelToken(function (cancelFn) {
    cancelToken = cancelFn
  })
}).catch(err = > {
  // 判断是否是cancelToken类型的取消
  if (!this.$axios.isCancel(err)) {
  }
 })

源码分析


## cancelToken

// 方案2
function CancelToken(executor) {
  if (typeof executor !== 'function') {
    throw new TypeError('executor must be a function.');
  }

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

  var token = this;
  executor(function cancel(message) {
    if (token.reason) {
      // Cancellation has already been requested
      return;
    }

    token.reason = new Cancel(message);
    // 可以在外部控制CancelToken内部的promise对象的resolve了。
    resolvePromise(token.reason);
  });
}

// 方案1
CancelToken.source = function source() {
  var cancel;
  var token = new CancelToken(function executor(c) {
    cancel = c;  // 将cancel函数赋值给cancel
  });
  return {
    token: token, // 返回的是CancelToken 实例, 需要使用内部的promise
    cancel: cancel  // 返回cancel函数
  };
};

CancelToken 初始化的时候需要传递一个方法executor,并且CancelToken内部新建了一个promise,最关键的是,它把promise的resolve方法控制权放在了executor方法里面, 使该promise能够在外部函数执行中进行resolve(也就是在cancel方法中可以使用)

参考

let resolveHandler;
new Promise((resolve) => {
    resolveHandle = resolve;
}).then((val) => {
    console.log('resolve',val);
});
resolveHandle('ok');

xhr

if (config.cancelToken) {
  // Handle cancellation
  // cancelToken.promise 中的原始resolve已经被赋值为resolvePromise,只有在cancel调用时候才会resolve
  config.cancelToken.promise.then(function onCanceled(cancel) {
    if (!request) {
      return;
    }

    // 取消请求
    request.abort();
    reject(cancel);
    // Clean up request
    request = null;
  });
}

当用户调用cancel方法后,则会resolve(CancelToken实例中promise的resolve) ,然后执行request.abort();

总结

1、核心就是将 CancelToken 中私有变量promise的resolve赋值给另一个变量resolvePromise, 2、然后在实例化CancelToken通过入参CancelToken 将 resolvePrimise的控制交给外部自定义函数 3、使promise能够被外部cancel函数中进行resolve的回调