前端开发中如何取消Promise操作

前端开发中如何取消Promise操作

前言

在 JavaScript 中,Promise 本身没有内置的取消机制,但我们可以通过一些模式来实现类似取消的功能。以下是几种常见的实现方式

方法一:使用 Promise.race() 模拟取消

Promise.race 静态方法接受一个 promise 可迭代对象作为输入,并返回一个 Promise。这个返回的 promise 会随着第一个 promise 的敲定而敲定。 那么我们可以传给它两个Promise,一个正常执行,一个我们将Promise的reject方法缓存下来,只需要在我们需要取消的时候调用即可

javascript 复制代码
// 封装取消函数
const cancelPromise = (promise) => {
  let cancel
  // 定义一个取消的Promise
  const rejectPromise = new Promise((_, reject) => {
    cancel = () => {
      reject({ name: 'cancel' })
    }
  })
  const resultPromise = Promise.race([promise, rejectPromise])
  return {
    cancel,
    promise: resultPromise
  }
}
const { cancel, promise } = cancelPromise(
  new Promise((resolve) => {
    // 3s之后完成
    setTimeout(() => {
      resolve({ data: [] })
    }, 3000)
  })
)
promise
  .then((res) => {
    console.log('Promise Resolve', res)
  })
  .catch((error) => {
    // 'cancel'
    console.log(error.name)
  })
setTimeout(() => {
  cancel()
}, 2000)

方法二:使用 AbortController(推荐)

AbortController 是一个构造函数,其signal我们可以传给fetch Api,然后我们只需要调用abort方法就可以取消该请求axios也支持该方法取消。

javascript 复制代码
const controller = new AbortController()
fetch('http://api.com/query', { signal: controller.signal })
  .then((res) => {
    console.log(res)
  })
  .catch((error) => {
    if (error.name === 'AbortError') {
      console.log('Promise 已取消')
    }
  })
// 超时取消
setTimeout(() => {
  controller.abort()
}, 2000)

被取消的请求会被浏览器标记为canceled

方法三:使用 Bluebird 库

Bluebird 是一个完善的Promise库,其完全遵循Promises/A+标准,所以我们可以像日常使用Promise一样使用他,而且它有许多超越原生Promise的功能、比如支持 Promise 取消、进度追踪、超时控制、更强大的错误处理机制(如 OperationalError)等。我们使用时候只需要安装后直接引入即可

csharp 复制代码
yarn add bluebird
javascript 复制代码
import Promise from 'bluebird'
...
// 打开取消功能
Promise.config({ cancellation: true })
const testPromise  = new Promise((resolve, reject, onCancel) => {
  setTimeout(() => {
    resolve('成功')
  }, 3000)
  onCancel(function () {
    console.log('promise 已被取消')
  })
})
  .then((res) => {
    console.log(res)
  }).finally(() => {
    // 判断Promise是否取消
    if(testPromise.isCancelled()) {
      console.log('promise 已被取消')
    }
  })
setTimeout(() => {
  // 取消Promise
  testPromise.cancel()
}, 1000)

可以看到正常使用和原生Promise并无区别,但是新增了onCancel、cancel、config等Api,简单介绍下

  • cancel:用于取消当前Promise
  • onCancel:Promise取消后会调用传入该方法的回调
  • isCancelled:判断Promise是否取消
  • config:配置项,因为取消Promise在当前版本中是默认关闭、传入cancellation: true打开取消功能

中文文档可以关注这里

总结与对比

在前端开发中,取消 Promise 操作是处理异步流程控制的重要能力。以下是各方案的对比:

方案对比

方案 优点 缺点 适用场景
Promise.race() 纯 JavaScript 实现,无需额外库 只是"模拟"取消,实际异步操作仍在执行 简单的取消需求,兼容性要求高
AbortController 原生支持,与 fetch API 深度集成 较新的 API,需要 polyfill 网络请求取消,现代浏览器项目
Bluebird 功能丰富,API 完善 需要引入第三方库,增加包体积 需要高级 Promise 功能的复杂应用

实践建议

  1. 现代项目首选 AbortController - 随着原生支持的普及,这是最标准和推荐的方式
  2. 简单场景用 Promise.race() - 对于简单的取消需求,这种方式足够且轻量
  3. 复杂异步流程考虑 Bluebird - 如果需要进度追踪、超时控制等高级功能

注意事项

  • 取消 Promise 并不意味着底层操作真的停止了(如定时器)
  • 要及时清理资源,避免内存泄漏
  • 在 React/Vue 等框架中,组件卸载时务必取消未完成的异步操作

选择合适的方法取决于具体需求、浏览器兼容性要求和项目架构。

相关推荐
掘金安东尼4 小时前
官方:什么是 Vite+?
前端·javascript·vue.js
柒崽4 小时前
ios移动端浏览器,vh高度和页面实际高度不匹配的解决方案
前端
渣哥4 小时前
你以为 Bean 只是 new 出来?Spring BeanFactory 背后的秘密让人惊讶
javascript·后端·面试
烛阴4 小时前
为什么游戏开发者都爱 Lua?零基础快速上手指南
前端·lua
大猫会长4 小时前
tailwindcss出现could not determine executable to run
前端·tailwindcss
Moonbit4 小时前
MoonBit Pearls Vol.10:prettyprinter:使用函数组合解决结构化数据打印问题
前端·后端·程序员
533_4 小时前
[css] border 渐变
前端·css
云中雾丽4 小时前
flutter的dart语言和JavaScript的消息循环机制的异同
前端
地方地方4 小时前
Vue依赖注入:provide/inject 问题解析与最佳实践
前端·javascript·面试