diff --git a/lib/internal/process/promises.js b/lib/internal/process/promises.js index 3da1011541bf9c..83dee491a55c90 100644 --- a/lib/internal/process/promises.js +++ b/lib/internal/process/promises.js @@ -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')) { + // 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; diff --git a/test/message/unhandled_promise_trace_warnings.js b/test/message/unhandled_promise_trace_warnings.js new file mode 100644 index 00000000000000..48450fb21e2169 --- /dev/null +++ b/test/message/unhandled_promise_trace_warnings.js @@ -0,0 +1,5 @@ +// Flags: --trace-warnings +'use strict'; +require('../common'); +const p = Promise.reject(new Error('This was rejected')); +setImmediate(() => p.catch(() => {})); diff --git a/test/message/unhandled_promise_trace_warnings.out b/test/message/unhandled_promise_trace_warnings.out new file mode 100644 index 00000000000000..80cf948cf118a3 --- /dev/null +++ b/test/message/unhandled_promise_trace_warnings.out @@ -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 *