前端开发中如何取消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 等框架中,组件卸载时务必取消未完成的异步操作

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

相关推荐
木易 士心10 小时前
Vue 3 Props 响应式深度解析:从原理到最佳实践
前端·javascript·vue.js
海鸥两三13 小时前
uniapp 小程序引入 uview plus 框架,获得精美的UI框架
前端·vue.js·ui·小程序·uni-app
lightgis14 小时前
16openlayers加载COG(云优化Geotiff)
前端·javascript·html·html5
小飞大王66614 小时前
TypeScript核心类型系统完全指南
前端·javascript·typescript
你的人类朋友16 小时前
✍️记录自己的git分支管理实践
前端·git·后端
合作小小程序员小小店17 小时前
web网页开发,在线考勤管理系统,基于Idea,html,css,vue,java,springboot,mysql
java·前端·vue.js·后端·intellij-idea·springboot
防火墙在线17 小时前
前后端通信加解密(Web Crypto API )
前端·vue.js·网络协议·node.js·express
Jacky-00817 小时前
Node + vite + React 创建项目
前端·react.js·前端框架
CoderYanger18 小时前
前端基础——CSS练习项目:百度热榜实现
开发语言·前端·css·百度·html·1024程序员节
i_am_a_div_日积月累_18 小时前
10个css更新
前端·css