-
Notifications
You must be signed in to change notification settings - Fork 30.1k
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: better stack traces for --trace-warnings #9525
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 |
---|---|---|
|
@@ -8,6 +8,11 @@ let lastPromiseId = 1; | |
|
||
exports.setup = setupPromises; | ||
|
||
function getAsynchronousRejectionWarningObject(uid) { | ||
return new Error('Promise rejection was handled ' + | ||
`asynchronously (rejection id: ${uid})`); | ||
} | ||
|
||
function setupPromises(scheduleMicrotasks) { | ||
process._setupPromises(function(event, promise, reason) { | ||
if (event === promiseRejectEvent.unhandled) | ||
|
@@ -31,10 +36,15 @@ function setupPromises(scheduleMicrotasks) { | |
const uid = promiseToGuidProperty.get(promise); | ||
promiseToGuidProperty.delete(promise); | ||
if (hasBeenNotified === true) { | ||
let warning = null; | ||
if (!process.listenerCount('rejectionHandled')) { | ||
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. Won't this always be hit because of the default listener? 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. @Fishrock123 Are you referring to the code in the block below this one? That’s not technically a listener, so it isn’t counted here. Also, at least a quick check in the REPL yields |
||
// Generate the warning object early to get a good stack trace. | ||
warning = getAsynchronousRejectionWarningObject(uid); | ||
} | ||
process.nextTick(function() { | ||
if (!process.emit('rejectionHandled', promise)) { | ||
const warning = new Error('Promise rejection was handled ' + | ||
`asynchronously (rejection id: ${uid})`); | ||
if (warning === null) | ||
warning = getAsynchronousRejectionWarningObject(uid); | ||
warning.name = 'PromiseRejectionHandledWarning'; | ||
warning.id = uid; | ||
process.emitWarning(warning); | ||
|
@@ -50,6 +60,9 @@ function setupPromises(scheduleMicrotasks) { | |
`(rejection id: ${uid}): ${reason}`); | ||
warning.name = 'UnhandledPromiseRejectionWarning'; | ||
warning.id = uid; | ||
if (reason instanceof Error) { | ||
warning.stack = reason.stack; | ||
} | ||
process.emitWarning(warning); | ||
if (!deprecationWarned) { | ||
deprecationWarned = true; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
// Flags: --trace-warnings | ||
'use strict'; | ||
require('../common'); | ||
const p = Promise.reject(new Error('This was rejected')); | ||
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 think the require('../common'); 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. @danbev right, done |
||
setImmediate(() => p.catch(() => {})); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
(node:*) Error: This was rejected | ||
at * (*test*message*unhandled_promise_trace_warnings.js:*) | ||
at * | ||
at * | ||
at * | ||
at * | ||
at * | ||
at * | ||
at * | ||
at * | ||
at * | ||
(node:*) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code. | ||
at * | ||
at * | ||
at * | ||
at * | ||
at * | ||
at * | ||
at * | ||
at * | ||
at * | ||
(node:*) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1) | ||
at getAsynchronousRejectionWarningObject (internal/process/promises.js:*) | ||
at rejectionHandled (internal/process/promises.js:*) | ||
at * | ||
at Promise.then (native) | ||
at Promise.catch (native) | ||
at Immediate.setImmediate (*test*message*unhandled_promise_trace_warnings.js:*) | ||
at * | ||
at * | ||
at * |
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.
Perhaps this could reduce late promise handling performance slightly but... oh well, maybe we can make that an option if people complain. ¯\_(ツ)_/¯ Good defaults are more important for this kind of thing.
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.
Maybe, but I think it’s okay. This should not be a hot path anyway.