axios 源码取消请求解析


axios有两种中断请求的方法

1.CancelToken.source   取消所有请求

const CancelToken = axios.CancelToken; const  source = CancelToken.source();

axios.post('/test', {   value: '测试' }, {   cancelToken: source.token })
source.cancel('取消请求');

 2. 通过 CancelToken 构造函数进行取消  取消单个请求

const CancelToken = axios.CancelToken;
let cancel;
axios.get("/test/user", {
    cancelToken: new CancelToken(function  executor(c){
        cancel = c
   }) 
})
 cancel("取消请求")

 主要代码:

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

  var resolvePromise;
    
//给实例绑定一个promise,promsie 状态为pending,只有调用resolvePromise 方法时this.promise变为fulfilled状态
  this.promise = new Promise(function promiseExecutor(resolve) {
    resolvePromise = resolve;
  });

  var token = this;

  // eslint-disable-next-line func-names
  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;
  });

  // eslint-disable-next-line func-names
  this.promise.then = function(onfulfilled) {
    var _resolve;
    // eslint-disable-next-line func-names
    var promise = new Promise(function(resolve) {
      token.subscribe(resolve);
      _resolve = resolve;
    }).then(onfulfilled);

    promise.cancel = function reject() {
      token.unsubscribe(_resolve);
    };

    return promise;
  };
    //通过Cancel函数创造一个取消原因信息
  executor(function cancel(message) {
    if (token.reason) {
      // Cancellation has already been requested
      return;
    }
        //token.reason 就是我们调用cancel方法时传递的信息  
    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
};
};

在CancelToken.js 中,发现上面两种中断请求的方法执行的都是同一个方法,

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

 token是指创建的CancelToken实例,判断是否有reason这个属性,有则说明已经发起取消请求了直接return,没有就通过Cancel 构造函数创建一个实例, 调用resolvePromise方法。

  var resolvePromise;

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

  在创建CancelToken 实例时,添加一个属性promise为Promsie的 实例,且状态为pending,将resolve 方法赋值给resolvePromise.这样resolvePromise 就像取消请求的开关,只有调用了resolvePromsie方法才能执行promise链.

if (config.cancelToken || config.signal) {
      // Handle cancellation
      // eslint-disable-next-line func-names
      onCanceled = function(cancel) {
        if (!request) {
          return;
        }
        reject(!cancel || (cancel && cancel.type) ? new Cancel('canceled') : cancel);
        request.abort();
        request = null;
      };
 config.cancelToken && config.cancelToken.subscribe(onCanceled);
CancelToken.prototype.subscribe = function subscribe(listener) {
  if (this.reason) {
    listener(this.reason);
    return;
  }

  if (this._listeners) {
    this._listeners.push(listener);
  } else {
    this._listeners = [listener];
  }
};

xhr.js根据cancelToken调用subscribe方法,当this.reason存在时调用 XMLhttpRquest 取消方法。this.reason就是前面Cancel生成的实例。

以上就是axios取消请求的基本流程。

相关