如何将async/await与Bluebird可取消Promise结合使用?
Bluebird Promise取消后await卡住的解决方案
问题场景
使用Bluebird实现可取消的异步操作时,调用cancel()后程序卡在await语句,后续代码完全无法执行,Promise始终处于pending状态。
问题代码
const Promise = require("bluebird"); Promise.config({ cancellation: true }); let myP = () => new Promise((resolve, reject, onCancel) => { // 模拟2秒异步操作 onCancel(() => { console.log("onCancel called"); }); setTimeout(function () { console.log("before resolve"); resolve("Success!"); }, 2500); }); const run = async () => { console.log("Start"); const prm = myP(); setTimeout(() => { prm.cancel(); }, 1000); await prm; console.log("After await prm"); // 永远不会执行 }; run() .then(() => console.log("Finished")) // 永远不会触发 .catch((e) => console.error(e));
问题根源
Bluebird的默认取消机制仅触发onCancel回调,但不会将Promise置为rejected状态。这导致Promise一直处于pending,await会无限等待,后续代码无法推进。
解决方法
在onCancel回调中主动调用reject,让Promise进入rejected状态,同时清理相关异步资源(比如定时器):
修改后的代码
const Promise = require("bluebird"); Promise.config({ cancellation: true }); let myP = () => new Promise((resolve, reject, onCancel) => { // 保存定时器ID用于后续清理 const timer = setTimeout(function () { console.log("before resolve"); resolve("Success!"); }, 2500); onCancel(() => { console.log("onCancel called"); // 清理定时器,避免资源浪费 clearTimeout(timer); // 主动reject,传递取消错误信息 reject(new Error("Promise已被取消")); }); }); const run = async () => { console.log("Start"); const prm = myP(); setTimeout(() => { prm.cancel(); }, 1000); try { await prm; console.log("After await prm"); } catch (e) { console.error("捕获到取消错误:", e.message); // 在这里处理取消后的业务逻辑 } }; run() .then(() => console.log("Finished")) .catch((e) => console.error("未处理的错误:", e));
关键细节
- 主动reject:让Promise结束pending状态,
await会捕获错误并进入catch分支,程序得以继续执行后续逻辑。 - 资源清理:取消时务必清理异步资源(如定时器、AJAX请求),防止内存泄漏。
- 错误捕获:在async函数中用try/catch包裹
await,针对性处理取消场景,不影响正常流程的执行。
内容的提问来源于stack exchange,提问作者stoefln
相关产品推荐
相关产品推荐

