前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库AbortController fetch
JavaScript异步与 Promise

怎么用 AbortController 取消 fetch 请求?

先 new 一个 AbortController,把它的 signal 传给 fetch,需要取消时调用 controller.abort()。请求会被中断,fetch 返回的 Promise 以 AbortError 拒绝。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#异步与 Promise#异步编程
先看核心答案读代码示例
理解线索

取消请求的三个角色

  1. AbortController遥控器,调用 abort() 发出取消信号
  2. signal传给 fetch 的接收器,被取消后 aborted 变成 true
  3. fetch收到信号就中断请求,Promise 以 AbortError 拒绝

取消只是让前端不再等这个响应,请求如果已经到了服务端,服务端照样会处理完。取消提交订单这类写操作,不能指望它回滚。

核心回答

先记住这个答案

AbortController 是浏览器原生的「取消器」。用法分三步:先 new AbortController(),再把 controller.signal 作为参数传给 fetch,要取消时调用 controller.abort()。fetch 收到信号后立刻中断请求,返回的 Promise 以名为 AbortError 的错误拒绝,所以 catch 里要把「主动取消」和「真的出错」区分开。

  • controller 负责喊停,signal 负责传话
  • abort() 后 fetch 以 AbortError 拒绝,要在 catch 里单独判断
  • 一个 controller 只能用一次,下次请求要 new 新的
  • 超时取消直接用 AbortSignal.timeout(ms)

最常见的用法:搜索框取消旧请求

用户快速输入 a、ab、abc,会连发三个请求。如果 a 的请求最慢,它最后回来就会把 abc 的结果盖掉。解决办法是每次发新请求前,先把上一次的取消掉。

每次输入前先取消上一次JavaScript
let controller = null

async function search(keyword) {
  controller?.abort() // 取消上一次还没回来的请求
  controller = new AbortController() // 一个 controller 只能用一次,每次都 new

  try {
    const res = await fetch(`/api/search?q=${encodeURIComponent(keyword)}`, {
      signal: controller.signal
    })
    render(await res.json())
  } catch (err) {
    if (err.name === 'AbortError') return // 主动取消的,不用提示用户
    showError(err)
  }
}

这样界面上永远只显示最后一次输入的结果。打开 Network 面板能看到被取消的请求状态是 canceled。 注意 await res.json() 读响应体的过程也会被中断,所以它要放在同一个 try 里。

超时取消和批量取消

fetch 自己没有 timeout 参数,以前要自己写 setTimeout 加 abort。现在浏览器提供了现成的静态方法,一行就够。

超时自动取消JavaScript
try {
  const res = await fetch('/api/report', {
    signal: AbortSignal.timeout(5000) // 5 秒还没回来就自动取消
  })
} catch (err) {
  // 超时触发的错误名是 TimeoutError,不是 AbortError
  if (err.name === 'TimeoutError') showError('请求超时,请重试')
}

超时报的是 TimeoutError,用户主动取消报的是 AbortError,这样就能给出不同的提示。

一个 signal 管多个请求
同一个 signal 可以同时传给好几个 fetch。比如一个页面同时拉了列表、详情、推荐三个接口,用户切走时调用一次 abort(),三个请求一起取消。React 里通常放在 useEffect 的清理函数里做:组件卸载时调用 controller.abort(),就不会出现「组件都没了,请求回来还在 setState」的情况。
让自己写的异步函数也支持取消
signal 不只 fetch 能用。自己封装的异步任务可以接收一个 signal,监听它的 abort 事件来停止工作,addEventListener 也支持传 signal,取消时自动移除监听。这样整条异步链路都能用同一个 controller 统一取消。
回答前,多想一步

容易答错的地方

以为取消了,服务端就不处理了
abort 只是让浏览器断开连接、不再等响应。请求如果已经发到服务端,服务端大概率照常执行完。所以提交订单、扣款这类写操作,取消请求不等于操作没发生,防重复提交还是要靠按钮禁用、幂等 key 这些手段。
复用同一个 controller
controller 被 abort 过一次,它的 signal 就永久处于已取消状态。拿它再发请求,fetch 会立刻拒绝。每次新请求都要 new 一个新的 controller。
catch 里不区分错误类型
取消是正常业务行为,不该弹「网络错误」。catch 里先判断 err.name === 'AbortError',是的话直接 return。
试着用自己的话回答

面试官还会怎么问?

axios 怎么取消请求?

axios 从 0.22 开始支持同样的写法,在配置里传 signal: controller.signal 即可,取消后 axios 抛出的错误可以用 axios.isCancel(err) 判断。以前的 CancelToken 写法已经废弃,新代码直接用 AbortController。

防抖和取消请求有什么区别,要一起用吗?

防抖是少发请求,停止输入 300 毫秒才发一次;取消是处理已经发出去的请求,防止旧结果覆盖新结果。防抖之后仍然可能有两个请求同时在路上,所以两个通常一起用。

不支持 signal 的老接口怎么防止旧结果覆盖?

给每次请求记一个递增的序号,结果回来时对比当前最新序号,不是最新的就丢弃。请求本身没取消,但旧数据不会再写进界面。

从一道题,走向一组知识

把知识连起来

异步与 Promise

async 函数里直接 throw 一个错误,调用方会怎么收到?

取消后 await 会抛错,可以顺便弄清 async 函数里的错误到底怎么传出来。

异步与 Promise

async 函数里 return 一个值,外面拿到的是值还是 Promise?

async 函数总是返回 Promise,取消请求时拿到的就是这个 Promise 的拒绝结果。

异步与 Promise

Promise 的状态只能改变一次,多次调用 resolve 或 reject 会怎样?

abort() 之后 Promise 变成 rejected,状态一旦改变就不会再变。

参考资料

  • JavaScript:异步与 Promise参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 最常见的用法:搜索框取消旧请求
  3. 超时取消和批量取消
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑