Bluebird seems to not handle async/await properly
See original GitHub issue-
What version of bluebird is the issue happening on? 3.5.4
-
What platform and version? (For example Node.js 0.12 or Google Chrome 32): Node v8 and Node v12
-
Did this issue happen with earlier version of bluebird? Also tried with v3.5.0 and same issue is occuring
The following code illustrates the issue. The code maked as from the 3rd party library is intended execute a series of promises in order (fooLoader, barLoader, bazLoader) where barLoader
should not execute until fooLoader
has resolved.
const log = (message: string) => {
// tslint:disable-next-line:no-console
console.log(`${new Date().toISOString()} ${message}`);
};
const sleep = (timeToSleepMs: number): Promise<void> => {
return new Promise<void>(res => setTimeout(res, timeToSleepMs));
};
// this code is taken from a 3rd party library
function runInSequence<T, U>(
collection: T[],
callback: (item: T) => Promise<U>
): Promise<U[]> {
const results: U[] = [];
return collection
.reduce((promise, item) => {
return promise
.then(() => {
return callback(item);
})
.then(result => {
results.push(result);
});
}, Promise.resolve())
.then(() => {
return results;
});
}
const fooLoader = async () => {
log("foo loader begin");
await sleep(1000);
log("foo loader complete");
};
const barLoader = async () => {
log("bar loader begin");
await sleep(2000);
log("bar loader complete");
};
const bazLoader = async () => {
log("baz loader begin");
await sleep(3000);
log("baz loader complete");
};
const runIt = (message: string) => {
return (
runInSequence([fooLoader, barLoader, bazLoader], loader => {
const loaderResult = loader();
return loaderResult instanceof Promise ? loaderResult : Promise.resolve();
})
.then(() => log(message))
// tslint:disable-next-line: no-console
.catch(err => console.error(err))
);
};
const runWithoutBluebird = () => {
log("running without Bluebird...");
return runIt("without bluebird complete");
};
const runWithBluebird = () => {
log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
log("running with Bluebird...");
const Promise = require("bluebird");
Promise.config({ longStackTraces: true });
global.Promise = Promise;
return runIt("with bluebird complete");
};
runWithoutBluebird()
.then(() => runWithBluebird())
// tslint:disable-next-line: no-console
.catch(err => console.error(err));
output:
2019-05-10T15:55:25.452Z running without Bluebird...
2019-05-10T15:55:25.456Z foo loader begin
2019-05-10T15:55:26.461Z foo loader complete
2019-05-10T15:55:26.462Z bar loader begin
2019-05-10T15:55:28.463Z bar loader complete
2019-05-10T15:55:28.464Z baz loader begin
2019-05-10T15:55:31.467Z baz loader complete
2019-05-10T15:55:31.467Z without bluebird complete
2019-05-10T15:55:31.467Z ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2019-05-10T15:55:31.467Z running with Bluebird...
2019-05-10T15:55:31.495Z foo loader begin
2019-05-10T15:55:31.495Z bar loader begin
2019-05-10T15:55:31.496Z baz loader begin
2019-05-10T15:55:31.496Z with bluebird complete
2019-05-10T15:55:32.498Z foo loader complete
2019-05-10T15:55:33.497Z bar loader complete
2019-05-10T15:55:34.499Z baz loader complete
Issue Analytics
- State:
- Created 4 years ago
- Comments:9
Top Results From Across the Web
ts-node not handling async/await properly with Bluebird #832
ts-node doesn't seem to be handling the resolution of promises correctly when using the Bluebird library globally.
Read more >Get Bluebird Promise from async await functions
The constructor seems enclosed: Note that AsyncFunction is not a global object. It could be obtained by evaluating the following code. Object.
Read more >petkaantonov/bluebird - Gitter
Hey, is there any way to tree shake the blue bird bundle to get the code which is needed for my usage. I...
Read more >Gary Bernhardt on Twitter: "Oh, async/await always use native ...
It seems like I can get it if I use Bluebird with "longStackTraces" enabled. ... app's JS context is probably the only way...
Read more >Promise.coroutine - Bluebird JS
Returns a function that can use yield to yield promises. Control is returned back to the generator when the yielded promise settles.
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Actually - never mind, scratch that. I see the issue.
You are using
instanceof Promise
to check if the result is an instance of Promise. Butasync
functions always return an instance of the native Promise, never of the patched up global. This is by spec.So then, you’re returning a
Promise.resolve()
in the runInSequence function for every loader, because the returned Promise isn’t a bluebird one, which is whatPromise
refers to after the patch.Modifying the runinsequence invocation to be:
solves the problem.
If you want to support non-async functions, I suggest instead of
instanceof
to useOr better yet, just
return Promise.resolve(p)
will auto-convert to promise only when needed.Ah…very interesting…and great catch! That code is actually from a 3rd party library (I just pulled it out to make the example standalone)…I will open a PR with them to make that change. Thanks @spion!