axios取消请求逻辑

axios是一款基于xml和 http请求对象 封装的请求库, 本文梳理其请求中断逻辑

1. 中断函数的使用: 

        

// 引入axios
const axios = require('axios');

// 创建取消令牌的源
const cancelTokenSource = axios.CancelToken.source();

// 发起一个请求
axios.get('https://example.com/api/data', {
  cancelToken: cancelTokenSource.token
}).then(response => {
  console.log('请求成功:', response.data);
}).catch(error => {
  if (axios.isCancel(error)) {
    console.log('请求被取消:', error.message);
  } else {
    // 处理其他错误
    console.error('请求出错:', error);
  }
});

// 如果需要取消请求
cancelTokenSource.cancel('取消请求,例如用户导航到其他页面');

2.  cancelToken的source作用如下

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

module.exports = CancelToken;

 new 出cancelToken的实例,定义executor函数,利用executor的形参获取到c, c为取消函数

3. cancelToken代码如下

// 文件路径 Axios/lib/cancel/CancelToken.js

// ...

/**
 * A `CancelToken` is an object that can be used to request cancellation of an operation.
 *
 * @class
 * @param {Function} executor The executor function.
 */
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;

  // 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) { // ...
  };

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

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

// ...


cancelToken类会立即执行 executor函数,将取消方法作为实参传递, source中cancel接到的形参便是executor中的cancel实参, 外部执行cancel执行的是resolvePromise方法

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

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

resolvePromise 用于存放cancelToken类中promise的resolve, promise用于控制中断相关操作的执行。 当resolvePromise执行, promsie被放行,则会执行cancelToken中的listeners

  var resolvePromise;

  this.promise = new Promise(function promiseExecutor(resolve) {
    resolvePromise = resolve;
  });
 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;
  });

listenters是注册的中断函数,注册方法如下: 

// 文件路径 Axios/lib/cancel/CancelToken.js

// ...

/**
 * Subscribe to the cancel signal
 */

CancelToken.prototype.subscribe = function subscribe(listener) {
  // reason 值不为 undefined 说明该请求已取消,可直接调用 listener
  if (this.reason) {
    listener(this.reason);
    return;
  }

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

// ...


4. 核心请求方法

// Axios/lib/adapters/xhr.js

// ...
    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);
      if (config.signal) {
        config.signal.aborted ? onCanceled() : config.signal.addEventListener('abort', onCanceled);
      }
    }
    
// ...

在走请求流程时,如果当前请求配置有cnacelToken, 定义onCanceled 中断函数,并通过subscribe注册到cancelToken类中, 等待resolvePromise 放行promise, 从而执行中断逻辑。

总结

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

 回顾一下source方法,

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

source返回了两个属性,

cancel是中断方法, 用于用户手动中断请求,

source.cancel('取消请求,例如用户导航到其他页面');

token为cancelToken实例, 显式的声明在axios请求上

axios.get('https://example.com/api/data', {
  cancelToken: cancelTokenSource.token
}).then

        当axios获取到cancelToken时,会定义中断请求的具体逻辑,通过cancelToken的 subscribe 进行订阅

        cancelToken类本身存在一个promise, resolve方法被存放在变量中, 当手动触发cancel方法时, resolve会放行, promsie.then会执行先前订阅的中断逻辑。 

        而中断逻辑则是给当前请求的promsie一个reject, 并且手动abort网络请求

 reject(!cancel || (cancel && cancel.type) ? new Cancel('canceled') : cancel);
 request.abort();
 request = null;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值