当前位置: 首页 > article >正文

axios 如何取消请求

axios 探索 如何取消 请求的

以 v0.x 版本为例 取消xhr 请求

先看看实际开发中,axios 是如何取消请求示例代码

import axios from 'axios';

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

axios.interceptors.request.use( (config) => {
        const xxx = config.headers.xxx;
        if (!xxx) {
            // 取消请求
            config.cancelToken = source.token;
            source.token.reason = {
                message: '登录过期',
            };
            source.cancel('登录过期');

            // 或者
            config.cancelToken = new axios.CancelToken(function executor(c) {
                c('登录过期')
            })
        }

        return config
    },
    error => {
        return Promise.reject(error)
    }
)

再先看xhr源码 中如何处理取消请求

lib\adapters\xhr.js

  • 发起ajax请求,
  • 判断 请求配置 config 中是否存在 cancelToken 如果存在那就
  • 调用 cancelToken.subscribe 方法,
  • onCanceled 方法 作为参数 传入

onCanceled 中 request.abort() 即为 XHR 取消请求的方法

    // 先判断 config.cancelToken 字段存在就会调用 config.cancelToken.subscribe 方法 
    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 CanceledError() : cancel);
        request.abort();
        request = null;
      };

      config.cancelToken && config.cancelToken.subscribe(onCanceled);
      if (config.signal) {
        config.signal.aborted ? onCanceled() : config.signal.addEventListener('abort', onCanceled);
      }
    }

    if (!requestData) {
      requestData = null;
    }

那我来具体看看 subscribe 做了什么事儿

可以看到 源码中,判断是否有取消的理由(即reason),存在 就会执行 listener (即外部传入的onCanceled),

lib\cancel\CancelToken.js

CancelToken.prototype.subscribe = function subscribe(listener) {
  if (this.reason) {
    listener(this.reason);
    return;
  }

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


关键点就是 this.reason 什么时候有值?

lib\cancel\CancelToken.js

当执行executor 的时候 reason 会 被赋值

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

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

完整的看一下源码
从 new CancelToken 开始

  • 给构造函数 CancelToken 原型上设置 subscribe 函数,用于添加订阅 监听器

  • 给构造函数 CancelToken 原型上设置 unsubscribe 函数,用于删除指定的监听器

  • new CancelToken 传入一个 回调函数 (executor )

  • 生成一个promise 对象

  • 重写 该promise 对象的then 方法

  • 给该promise 设置 then 回调函数

  • 执行 executor 函数,传入 cancel 函数(即取消函数)


当我们 构造 CancelToken 实例(cancelToken) 传入 executor 函数,从executor中拿到 cancel 函数,执行 cancel函数,会导致 CancelToken 实例中,reaseon被赋值, promose对象 状态变为 fulfilled 状态,然后执行promise实例的then 回调, 执行内部所有 监听器 listeners,当发起xhr请求时判断 config.cancelToken 调用 subscribe 时,reason 已经被赋值了,就会直接执行 config.cancelToken(onCanceled) 中的 onCanceled 方法 取消 xhr 请求

lib\cancel\CancelToken.js

'use strict';

var CanceledError = require('./CanceledError');

/**
 * 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) {
    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);
    resolvePromise(token.reason);
  });
}

/**
 * Throws a `CanceledError` if cancellation has been requested.
 */
CancelToken.prototype.throwIfRequested = function throwIfRequested() {
  if (this.reason) {
    throw this.reason;
  }
};

/**
 * Subscribe to the cancel signal
 */

CancelToken.prototype.subscribe = function subscribe(listener) {
  if (this.reason) {
    listener(this.reason);
    return;
  }

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

/**
 * Unsubscribe from the cancel signal
 */

CancelToken.prototype.unsubscribe = function unsubscribe(listener) {
  if (!this._listeners) {
    return;
  }
  var index = this._listeners.indexOf(listener);
  if (index !== -1) {
    this._listeners.splice(index, 1);
  }
};

/**
 * Returns an object that contains a new `CancelToken` and a function that, when called,
 * cancels the `CancelToken`.
 */
CancelToken.source = function source() {
  var cancel;
  var token = new CancelToken(function executor(c) {
    cancel = c;
  });
  return {
    token: token,
    cancel: cancel
  };
};

module.exports = CancelToken;


http://www.kler.cn/a/375274.html

相关文章:

  • Spring 设计模式之适配器模式
  • 光纤中光的散射
  • 【前端】在 Next.js 开发服务器中应该如何配置 HTTPS?
  • node.js_npm : 无法加载文件 D:\Program Files\nodejs\npm.ps1
  • AWS EC2 AMI 跨账号备份解决方案文档
  • django5入门【04】Django框架配置文件说明:settings.py
  • 移植 AWTK 到 纯血鸿蒙(HarmonyOS NEXT)系统 (0) - 序
  • IP 欺骗以及其他常见网络攻击手段(附hping3的实际应用)
  • Qml-Gif的显示
  • 13 实战:使用Python和Pygame实现视频运动估计播放器
  • 二维legendre多项式
  • Oracle 第10章:触发器
  • 关于校验码的算法
  • 《向量数据库指南》——解锁GenAI生态系统新纪元
  • 面试题整理 2
  • 金蝶云星空与致远OA集成:简化审批流程,提升效率,确保数据一致性
  • SpringBoot实现zip压缩包下载
  • sprintf函数使用指南
  • 0.STM32F1移植到F0的各种经验总结
  • html中cookie如何存储
  • ChatGPT-o1在辅助论文参考文献写作中的表现如何?有哪些提升?
  • 整车功能架构 --- 智能座舱
  • 红日安全-ATT CK实战:Vulnstack靶场实战
  • 深度学习之降维和聚类
  • 【数据库系统概论】第3章 关系数据库标准语言SQL(一)数据查询(超详细)
  • 中仕公考:25年上海省考时间