From 991d9e290917cc9ae4a790108782a3231e6c0852 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Wed, 9 Nov 2016 02:04:04 +0100 Subject: [PATCH 1/2] promise: better stack traces for --trace-warnings Give better stack traces for `PromiseRejectionHandledWarning` and `UnhandledPromiseRejectionWarning`s. For `PromiseRejectionHandledWarning`, when it is likely that there is an `Error` object generated, it is created early to provide a proper stack trace. For `UnhandledPromiseRejectionWarning`, the stack trace of the underlying error object is used, if possible. Fixes: https://github.com/nodejs/node/issues/9523 --- lib/internal/process/promises.js | 17 ++++++++-- .../unhandled_promise_trace_warnings.js | 4 +++ .../unhandled_promise_trace_warnings.out | 31 +++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 test/message/unhandled_promise_trace_warnings.js create mode 100644 test/message/unhandled_promise_trace_warnings.out 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..1857b113c5b7d0 --- /dev/null +++ b/test/message/unhandled_promise_trace_warnings.js @@ -0,0 +1,4 @@ +// Flags: --trace-warnings +'use strict'; +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 * From de662aefd7a81a3e2be851652ad38d6ca4265022 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Wed, 9 Nov 2016 11:21:05 +0100 Subject: [PATCH 2/2] address nit --- test/message/unhandled_promise_trace_warnings.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/message/unhandled_promise_trace_warnings.js b/test/message/unhandled_promise_trace_warnings.js index 1857b113c5b7d0..48450fb21e2169 100644 --- a/test/message/unhandled_promise_trace_warnings.js +++ b/test/message/unhandled_promise_trace_warnings.js @@ -1,4 +1,5 @@ // Flags: --trace-warnings 'use strict'; +require('../common'); const p = Promise.reject(new Error('This was rejected')); setImmediate(() => p.catch(() => {}));