Skip to content
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

Unhandled promise rejection when promise is not currently being await-ed on #4286

Closed
ghost opened this issue Nov 6, 2023 · 4 comments
Closed

Comments

@ghost
Copy link

ghost commented Nov 6, 2023

Details

The following code will trigger an unhandled promise rejection.

Firefox has the same behavior.

Chrome however is interesting. At first Chrome console shows a red error but then Chrome changes its mind.

I'm just trying to understand why. I mean, logically it should work as the promise being rejected is eventually await-ed on later. But it seems like rejections must be await-ed on as they happen?

Node.js version

Not applicable.

Example code

(async () => {
	try {
		const promise = new Promise((resolve, reject) => {
			reject(new Error("oops"));
		});

		// Uncomment this to get a unhandled promise rejection.
		// await new Promise((resolve) => setTimeout(resolve, 1000)});

		await promise;
	} catch (reason) {
		console.log("caught the error");
	}
})();

Operating system

Not applicable.

Scope

Not applicable.

Module and version

Not applicable.

@ghost ghost changed the title Unhandled promise rejection when promise is not not currently being await-ed on Unhandled promise rejection when promise is not currently being await-ed on Nov 6, 2023
@ljharb
Copy link
Member

ljharb commented Nov 6, 2023

In browsers, the console can be asynchronously updated; in node, it can not.

Promise unhandled rejection hooks were designed for (and really, only intended for use in) browsers, precisely because of this issue. Since node has chosen to implement these hooks, they will give false positives for a rejected promise that's handled later, and that's just unavoidable.

@ghost
Copy link
Author

ghost commented Nov 7, 2023

I come from a C++ background. In C++, promises are just containers whose state will be determined later. Nothing happens until the promise is observed.

In Javascript it appears that promises are implemented with a default catch that will throw an uncaught promise rejection.

While (some) browsers may decide to update the console (like you mentioned) when the promise rejection is eventually handled, an unhandled rejected exception was thrown (causing the error to be displayed, if only for a while) and any user-defined handler will have triggered.

This makes logically sound code as per the example break in unexpected ways. To solve this problem, I have to either write non-async/await code with .then() / .catch() chains which makes me sad. Or wrap the whole thing in Promise.all() and IIFE's which hurts readability.

I honestly don't know whether this is a language issue, specification issue or node issue. I've seen lots of code examples do the exact same thing so I'm clearly not the only one thinking that "I'll just await the promise later" will work. To me this very much looks like a footgun.

@ljharb
Copy link
Member

ljharb commented Nov 7, 2023

It’s a node issue, and yes, it’s a footgun. You can disable or change the unhandled rejection behavior with a flag, or by adding your own unhandled rejection event listener.

All browsers behave the same here, as the HTML spec requires it; the language spec merely allows implementations to do it (largely because there’s no good way to allow what browsers do while prohibiting what node does).

@ghost
Copy link
Author

ghost commented Nov 8, 2023

Fair enough. Thanks for your comments.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant