-
Notifications
You must be signed in to change notification settings - Fork 29.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unexpected await and Promise behavior #31392
Comments
Duplicate of nodejs/promises-debugging#16 |
@nodejs/assert should |
What do you mean by “a check”? Like, if they haven’t settled by the time the process exits, they throw? |
@ljharb yes |
For other people trying to work around this issue, here is a clever way to assert if a promise is resolved or rejected, that won't silently let you down if it's never either: await assert.rejects(Promise.race([
// Promise instance to assert.
promise,
// Thoeretically you could use any value except Promise.reject() here.
Promise.resolve()
])) This is only a solution if you want to assert the status at an instant in time; it won't wait around to check how the promise eventually settles. Maybe this could pattern could be available as a new await assert.rejected(promise) The past-tense naming makes it obvious the assertion won't wait around for a promise to settle. |
relacted: #29355 |
I think they probably should. |
Could I take this issue? Try to implement the warning about unresolved promises mentioned here |
@conordavenport ... this could be a good one, yes, but it could be tricky. In most cases when Node.js exits normally, the The idea here would be for This also raises a question: What if there are multiple unsettled promises at Promise exit? Do we just throw a single Assertion error? Do we print multiple warnings? etc. Before doing the implementation on this time should be taken on what the expected experience should be. |
Also note: it would be fairly trivial for user code to implement a rudimentary Promise status tracker using the async_hooks API. |
I wouldn’t throw anything from a |
Thinking about this further, porting the doAsyncThing().finally(assert.mustCall()) @addaleax's warning about throwing in process exit is valid, however... so rather than throwing an assertion error on |
Doing this record keeping correctly also leads to massive memory leaks when there are many unresolved promises, even more so if it also retains call stacks. IMO, a better approach is to invest effort in improving the debugger experience for promises. For example, showing the 25 longest-living promises in the debugger will probably go a long way towards tracking down bugs, and that's something that can be implemented with a simple generation counter. |
Using
await
on aPromise
that never resolves or rejects behaves very strangely. I would expect it to simply hang, indefinitely awaiting the promise.What actually happens is that the rest of the script outside the async function carries on normally, and the process exits fast and without an error.
Result:
It's concerning that in the case of demo 2, a test could in a way be skipped at the point of a
rejects
assertion, without any exception or warning even though the promise never actually rejected.I would prefer
await
on a promise that never resolves or rejects hangs indefinitely, that way when testing locally you can tell something is wrong, and CI can timeout and exit with an error.Tweet thread: https://twitter.com/jaydenseric/status/1217964277727809536
The text was updated successfully, but these errors were encountered: