You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过AbortController.abort的reason参数区分fetch中止场景?

解决Fetch中止时传递自定义中止原因的问题

原生Fetch API在被AbortController.abort()中止时,catch语句里只会收到固定的DOMException('The user aborted a request', 'ABORT_ERROR'),不管你调用abort()时传入什么reason参数,这个错误都不会携带自定义信息。要区分用户主动点击中止和页面跳转两种场景,你可以通过封装Fetch请求的方式,自己关联中止原因:

方法一:标记中止类型后关联到错误

封装一个请求函数,在调用中止方法时标记是用户主动操作还是页面跳转,然后在catch阶段把这个标记附加到错误对象上:

function fetchWithAbortType(url, options = {}) {
  const controller = new AbortController();
  let isUserInitiatedAbort = false;

  options.signal = controller.signal;

  const requestPromise = fetch(url, options)
    .catch(error => {
      if (error.name === 'AbortError') {
        error._isUserAbort = isUserInitiatedAbort;
      }
      throw error;
    });

  return {
    promise: requestPromise,
    abort: (userInitiated = false) => {
      isUserInitiatedAbort = userInitiated;
      controller.abort();
    }
  };
}

使用示例

// 发起请求
const { promise, abort } = fetchWithAbortType('/whatever');

// 用户点击中止按钮
document.querySelector('#abort-btn').addEventListener('click', () => {
  abort(true); // 标记为用户主动中止
});

// 页面跳转时触发中止
function handlePageNavigation() {
  abort(false); // 标记为页面跳转导致的中止
}

// 处理请求结果
promise
  .then(res => res.json())
  .catch(error => {
    if (error.name === 'AbortError') {
      if (error._isUserAbort) {
        // 显示UI提示
        alert('call /whatever interrupted');
      }
      // 页面跳转导致的中止则不做UI处理
    } else {
      console.error('请求失败:', error);
    }
  });

方法二:捕获AbortSignal的自定义reason

AbortController.abort(reason)传入的参数,会被存在signal.reason里,你可以监听signal的abort事件提前保存这个reason,再在catch阶段附加到错误上:

function fetchWithCustomReason(url, options = {}) {
  const controller = new AbortController();
  let abortReason = null;

  controller.signal.addEventListener('abort', () => {
    abortReason = controller.signal.reason;
  });

  options.signal = controller.signal;

  return {
    promise: fetch(url, options).catch(error => {
      if (error.name === 'AbortError' && abortReason) {
        error.customReason = abortReason;
      }
      throw error;
    }),
    abort: (reason) => controller.abort(reason)
  };
}

使用示例

const { promise, abort } = fetchWithCustomReason('/whatever');

// 用户主动中止
document.querySelector('#abort-btn').addEventListener('click', () => {
  abort('user-interrupted');
});

// 页面跳转中止
function handlePageNavigation() {
  abort('page-navigation');
}

promise
  .then(res => res.json())
  .catch(error => {
    if (error.name === 'AbortError') {
      if (error.customReason === 'user-interrupted') {
        alert('call /whatever interrupted');
      }
    }
  });

这两种方法都能绕过原生Fetch的限制,让你在catch阶段区分不同的中止场景,按需处理UI提示。

内容的提问来源于stack exchange,提问作者Marco Faustinelli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 09:06:35