AXIOS cancelToken使用和原理

3,498 阅读1分钟

一、使用方法

  • 取消单个请求 通过传递一个 executor 函数到 CancelToken 的构造函数来创建 cancel token:
const CancelToken = axios.CancelToken; 
let cancel; 
axios.get('/user/12345', {   
    cancelToken: new CancelToken(function executor(c) {     
    // executor 函数接收一个 cancel 函数作为参数     
    cancel = c;   
    })
});  
cancel();//取消
  • 同时取消多个请求
const CancelToken = axios.CancelToken; 
const source = CancelToken.source();  
   axios.get('/user/12345', {   
       cancelToken: source.token 
   }).catch(function(thrown) {   
       if (axios.isCancel(thrown)) {     
       console.log('Request canceled', thrown.message);   
       } else {     
         // 处理错误  
       } 
   });
   axios.get('/user/123456', {   
       cancelToken: source.token 
   })
   
   axios.post('/user/12345', {   
    name: 'new name' 
   }, {   
    cancelToken: source.token 
   })  
 // 取消请求(message 参数是可选的) 
source.cancel('Operation canceled by the user.');

二、基本原理

canceltoken 是通过发布订阅模式实现的,将axios.CancelToken构造器的实例通过cancelToken传入,就会调用实例上的subscribe方法订阅取消消息,再根据需求执行cancel方法触发订阅器取消请求。

  • 核心代码

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;

  // _listeners 是一个存放订阅器的数组
  //cancel调用后执行 _listeners里面的订阅器
  this.promise.then(function(cancel) {
    if (!token._listeners) return;

    var i;
    var l = token._listeners.length;

    for (i = 0; i < l; i++) {
      token._listeners[i](cancel);
    }
    token._listeners = null;
  });
  
  //cancel方法里面调用promise的resolve
  executor(function cancel(message) {
    if (token.reason) {
      // Cancellation has already been requested
      return;
    }

    token.reason = new CanceledError(message);
    resolvePromise(token.reason);
  });
}

  • 原型方法

  1. throwIfRequested:如果请求已经取消或者请求完毕就会触发调用
  2. subscribe:将订阅器添加到_listeners里面
.../lib/adapters/xhr.js
function xhrAdapter(config) {
   return new Promise(function dispatchXhrRequest(resolve, reject) {
     ...
     if (config.cancelToken || config.signal) { 
        onCanceled = function(cancel) {
          if (!request) {
            return;
          }
          reject(!cancel || (cancel && cancel.type) ? new CanceledError() : cancel);
          request.abort();
          request = null;
        };

        config.cancelToken && config.cancelToken.subscribe(onCanceled);
    }
   }
}

3.unsubscribe:取消订阅(接口请求完成都会调用)

  • source方法

返回一个具有token和cancel属性的对象,都是通过CancelToken这个构造函数来的,

CancelToken.source = function source() {
  var cancel;
  var token = new CancelToken(function executor(c) {
    cancel = c;
  });
  return {
    token: token,
    cancel: cancel
  };
};