-
Notifications
You must be signed in to change notification settings - Fork 29.8k
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
promise: warn on unhandled rejections #6439
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,9 @@ | |
|
||
const promiseRejectEvent = process._promiseRejectEvent; | ||
const hasBeenNotifiedProperty = new WeakMap(); | ||
const promiseToGuidProperty = new WeakMap(); | ||
const pendingUnhandledRejections = []; | ||
let lastPromiseId = 1; | ||
|
||
exports.setup = setupPromises; | ||
|
||
|
@@ -18,32 +20,42 @@ function setupPromises(scheduleMicrotasks) { | |
|
||
function unhandledRejection(promise, reason) { | ||
hasBeenNotifiedProperty.set(promise, false); | ||
promiseToGuidProperty.set(promise, lastPromiseId++); | ||
addPendingUnhandledRejection(promise, reason); | ||
} | ||
|
||
function rejectionHandled(promise) { | ||
var hasBeenNotified = hasBeenNotifiedProperty.get(promise); | ||
if (hasBeenNotified !== undefined) { | ||
hasBeenNotifiedProperty.delete(promise); | ||
const uid = promiseToGuidProperty.get(promise); | ||
promiseToGuidProperty.delete(promise); | ||
if (hasBeenNotified === true) { | ||
process.nextTick(function() { | ||
process.emit('rejectionHandled', promise); | ||
if(!process.emit('rejectionHandled', promise)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
process.emitWarning('Promise Rejection Handled Asynchronously' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. feels a bit weird that this warns? |
||
+ '(rejection id: ' + uid +') ', | ||
'PromiseRejectionHandledWarning'); | ||
} | ||
}); | ||
} | ||
|
||
} | ||
} | ||
|
||
function emitPendingUnhandledRejections() { | ||
var hadListeners = false; | ||
let hadListeners = false; | ||
while (pendingUnhandledRejections.length > 0) { | ||
var promise = pendingUnhandledRejections.shift(); | ||
var reason = pendingUnhandledRejections.shift(); | ||
const promise = pendingUnhandledRejections.shift(); | ||
const reason = pendingUnhandledRejections.shift(); | ||
if (hasBeenNotifiedProperty.get(promise) === false) { | ||
hasBeenNotifiedProperty.set(promise, true); | ||
const uid = promiseToGuidProperty.get(promise); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
if (!process.emit('unhandledRejection', reason, promise)) { | ||
// Nobody is listening. | ||
// TODO(petkaantonov) Take some default action, see #830 | ||
process.emitWarning('Possibly unhandled promise rejection ' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we should double emit. Why not just print it, or use the internal warning logic directly? I also definitely don't think this should be "catchable" in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, the point of this PR was to use @jasnell's idea of treating them as warnings. If we consider them warning and not errors initially I see double benefit: A) It's theoretically sound, since we're not claiming it's an error but a warning (like adding a lot of listeners to an EventEmitter). Note that rejections are pretty rare (like actual exceptions) and unhandled rejections even more so - so the performance penalty here is negligible. By emitting a warning rather than directly printing an error - I think we're leaving a much bigger opportunity for a long term solution: people realize warnings might go away, can be turned off, can be reported to another channel than errors and so on. This does not contradict a "throw on unhandled GC" or another "long term" solution. It does solve the problem of promises being terribly hard for users to debug with the current default which is what people always complain about in StackOverflow and forums. I think it's a reasonable compromise and that we haven't been fair to our users since we landed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could potentially check the listener count for unhandledRejection first and only emit if it's greater than zero, otherwise emit the warning. This is precisely the kind of thing emitWarning is for. -1 for printing directly. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm happy with I'd quibble that we should probably log this as an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jasnell what you are describing is exactly the behavior in this PR, emitWarning is only called if there are no There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @chrisdickinson's point makes sense. |
||
+ '(rejection id: ' + uid +'): ' | ||
+ reason, | ||
'UnhandledPromiseRejectionWarning'); | ||
} else { | ||
hadListeners = true; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var
is a little more efficient still iirc