I have an async operation that should be cancelable. So I decided to use Bluebird Promises to get it done.
However, when I try to run it, my code never completes, because (in case of the promise being canceled) everything gets stuck at "await".
Do you have any elegant solution for this problem?
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));
2
Answers
You can invoke
reject()
in the onCancel callback and catch the exception by wrapping theawait prm
with try catch block or just let it throw:And Keith is right in the comment. You can use a
AbortController
.ES6 has this already built in
AbortController
, it’s maybe not obvious it can be used for other things, not just for fetch.Below is your example using the
AbortController
.Please note, when you abort, it’s your responsibility to either
reject
orresolve
to keep code flowing. In most cases I usually reject, and if required catch this error as normal.ps. I also updated to make abort cancel the timeOut too, as for some reason you missed that bit out in your example.
ps. It’s also possible to use 1 signal to cancel multiple promises, in this case it’s usually better to use
addEventListener('abort', e)
instead ofsig.onabort = e