其他分享
首页 > 其他分享> > Axios取消请求以及其原理(v0.26.1)

Axios取消请求以及其原理(v0.26.1)

作者:互联网

Axios取消请求以及其原理(v0.26.1)

1. 取消请求

const axios = require('axios')

const instance = new axios.Axios({})
// 创建source,通过source.cancel()取消请求
const source = new axios.CancelToken.source()

instance.defaults.timeout = 10000

instance.interceptors.request.use(
  config => {
    config.cancelToken = source.token
    return config
  }
)

// 此处写了两个响应拦截器是测试用,
// 因为我在项目中看到他人
// 定义了一个全局的CancelToken.source。当请求失败
// 报错后执行source(),使config.token.reason.message = undefined
// dispatchRequest时会调用CancelToken.prototype.throwIfRequested方法,
// 直接抛出异常信息config.token.reason,不发送ajax请求
instance.interceptors.response.use(
  ({ data, status, statusText }) => {
    if (status < 200 || status > 399) {
      throw statusText
    }
    return data
  }
)
instance.interceptors.response.use(
  undefined,
  error => {
    // 取消请求
    source.cancel()
    throw error
  }
)

2. 取消请求的原理

调用 CancelToken.source.cancel方法 时,将 CancelToken实例 上的 promise 属性的状态改为 fulfilled

CancelToken.source方法

CancelToken.source = function source() {
  var cancel;
  // 用cancel保存executor中的方法c方法,执行cancel()时,会将token.promise的状态变为fulfilled
  var token = new CancelToken(function executor(c) {
    cancel = c;
  });
  return {
    token: token,
    cancel: cancel
  };
};

CancelToken构造函数

function CancelToken(executor) {
  // 此处省略executor须为function类型的校验

  // 用resolvePromise保存Promise中的resolve方法,在执行source.cancel()的时候调用
  var resolvePromise;
  this.promise = new Promise((resolve) => {
    resolvePromise = resolve;
  });

  var token = this;

  // promise的状态变为fulfilled时,遍历_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;
  });

  
  // 重写promise.then方法
  // 若已取消请求,会在token.subscribe方法中执行resolve(this.reason)
  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;
  };

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

    token.reason = new CanceledError(message);
    // 改变token.promise的状态为fulfilled
    resolvePromise(token.reason);
  });
}

CancelToken.prototype.subscribe方法

/**
 *  利用发布订阅者模式,收集回调(执行xhr.abort方法)
 */
CancelToken.prototype.subscribe = function subscribe(listener) {
  // 如果有reason,说明请求已取消,立即执行listener
  if (this.reason) {
    listener(this.reason);
    return;
  }

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

明白以上逻辑后,剩下要做的就是订阅 xhr.abort方法

标签:Axios,请求,source,token,resolve,promise,cancel,v0.26,CancelToken
来源: https://www.cnblogs.com/alison1996/p/16163282.html