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));
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
or resolve
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.
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));
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 of sig.onabort = e