前端开发中如何取消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 功能的复杂应用 |
实践建议
- 现代项目首选 AbortController - 随着原生支持的普及,这是最标准和推荐的方式
- 简单场景用 Promise.race() - 对于简单的取消需求,这种方式足够且轻量
- 复杂异步流程考虑 Bluebird - 如果需要进度追踪、超时控制等高级功能
注意事项
- 取消 Promise 并不意味着底层操作真的停止了(如定时器)
- 要及时清理资源,避免内存泄漏
- 在 React/Vue 等框架中,组件卸载时务必取消未完成的异步操作
选择合适的方法取决于具体需求、浏览器兼容性要求和项目架构。