提问人:stoefln 提问时间:5/31/2023 更新时间:5/31/2023 访问量:143
如何将异步 await 与 Bluebird 可取消承诺相结合
How to combine async await with Bluebird cancelable promises
问:
我有一个应该可以取消的异步操作。所以我决定使用Bluebird Promises来完成它。 但是,当我尝试运行它时,我的代码永远不会完成,因为(如果承诺被取消)一切都停留在“等待”状态。
对于这个问题,你有什么优雅的解决方案吗?
Codesandbox:https://codesandbox.io/p/sandbox/bluebird-playground-forked-dfbp61?welcome=true
const Promise = require("bluebird");
Promise.config({ cancellation: true });
let myP = () =>
new Promise((resolve, reject, onCancel) => {
// In this example, we use setTimeout(...) to simulate async code that runs 2 seconds
onCancel(() => {
console.log("onCancel called");
});
setTimeout(function () {
console.log("before resolve");
resolve("Success!"); // Yay! Everything went well!
}, 2500);
});
const run = async () => {
console.log("Start");
const prm = myP();
setTimeout(() => {
prm.cancel();
}, 1000);
await prm;
console.log("After await prm"); // <- this code is never executed, what can I do?
};
run()
.then(() => console.log("Finished")) // <- "then" is never called, what can I do?
.catch((e) => console.error(e));
答:
0赞
Matt Peng
5/31/2023
#1
您可以在 onCancel 回调中调用并通过包装 with try catch 块来捕获异常,或者让它抛出:reject()
await prm
const Promise = require("bluebird");
Promise.config({ cancellation: true });
let myP = () =>
new Promise((resolve, reject, onCancel) => {
onCancel(() => {
console.log("onCancel called");
reject();
});
setTimeout(() => resolve("Success!"), 2500);
});
const run = async () => {
console.log("Start");
const prm = myP();
setTimeout(() => prm.cancel(), 1000);
await prm;
};
run()
.then(() => console.log("Finished"))
.catch((e) => console.error(e));
基思在评论中是对的。您可以使用 .AbortController
const controller = new AbortController();
let myP = (sig) =>
new Promise((resolve, reject) => {
if (sig?.aborted) return reject()
let timer
timer = setTimeout(() => resolve("Success!"), 2500);
function handleAbort() {
clearTimeout(timer)
signal?.removeEventListener("abort", handleAbort)
reject()
}
signal?.addEventListener("abort", handleAbort);
});
const run = async () => {
console.log("Start");
const prm = myP(controller.signal);
setTimeout(() => controller.abort(), 1000);
await prm;
};
run()
.then(() => console.log("Finished"))
.catch((e) => console.error(e));
评论
0赞
stoefln
5/31/2023
你的例子不起作用。“After await prm”永远不会被记录。
0赞
Matt Peng
5/31/2023
@stoefln会抛出错误?如果是这样,请用 try catch 块包装它。await prm
0赞
stoefln
5/31/2023
自己试试吧。这是行不通的。
2赞
Keith
5/31/2023
#2
ES6 已经内置了这一点,它可能不明显可以用于其他事情,而不仅仅是用于获取。AbortController
下面是使用 .AbortController
请注意,当您中止时,您有责任或保持代码流动。在大多数情况下,我通常会拒绝,如果需要,我会像往常一样发现这个错误。reject
resolve
我还更新了使中止取消超时,因为出于某种原因,您在示例中错过了这一点。
let myP = (sig) =>
new Promise((resolve, reject) => {
const tm = setTimeout(function () {
console.log("before resolve");
resolve("Success!"); // Yay! Everything went well!
}, 2500);
//sig.onabort = () => {
sig.addEventListener('abort', () => {
console.log('aborted');
clearTimeout(tm);
resolve();
});
});
const run = async () => {
console.log("Start");
const sig = new AbortController();
const prm = myP(sig.signal);
setTimeout(() => sig.abort(), 1000);
await prm;
console.log("After await prm");
};
run()
.then(() => console.log("Finished"))
.catch((e) => console.error(e));
也可以使用 1 个信号来取消多个 promise,在这种情况下,通常最好使用 而不是addEventListener('abort', e)
sig.onabort = e
评论