promise: warn on unhandled rejections
Log unhandled promise rejections with a guid and emit a process warning. When rejection is eventually handled, emit a secondary warning. PR-URL: https://github.com/nodejs/node/pull/8217 Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
This commit is contained in:
parent
488d37b3dc
commit
ecf474ceba
@ -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,6 +20,7 @@ function setupPromises(scheduleMicrotasks) {
|
||||
|
||||
function unhandledRejection(promise, reason) {
|
||||
hasBeenNotifiedProperty.set(promise, false);
|
||||
promiseToGuidProperty.set(promise, lastPromiseId++);
|
||||
addPendingUnhandledRejection(promise, reason);
|
||||
}
|
||||
|
||||
@ -25,9 +28,17 @@ function setupPromises(scheduleMicrotasks) {
|
||||
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)) {
|
||||
const warning = new Error('Promise rejection was handled ' +
|
||||
`asynchronously (rejection id: ${uid})`);
|
||||
warning.name = 'PromiseRejectionHandledWarning';
|
||||
warning.id = uid;
|
||||
process.emitWarning(warning);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -35,15 +46,19 @@ function setupPromises(scheduleMicrotasks) {
|
||||
}
|
||||
|
||||
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);
|
||||
if (!process.emit('unhandledRejection', reason, promise)) {
|
||||
// Nobody is listening.
|
||||
// TODO(petkaantonov) Take some default action, see #830
|
||||
const warning = new Error('Unhandled promise rejection ' +
|
||||
`(rejection id: ${uid}): ${reason}`);
|
||||
warning.name = 'UnhandledPromiseRejectionWarning';
|
||||
warning.id = uid;
|
||||
process.emitWarning(warning);
|
||||
} else {
|
||||
hadListeners = true;
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
// Flags: --no-warnings
|
||||
'use strict';
|
||||
|
||||
// Test that warnings are emitted when a Promise experiences an uncaught
|
||||
// rejection, and then again if the rejection is handled later on.
|
||||
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
|
||||
var b = 0;
|
||||
|
||||
process.on('warning', common.mustCall((warning) => {
|
||||
switch (b++) {
|
||||
case 0:
|
||||
assert.strictEqual(warning.name, 'UnhandledPromiseRejectionWarning');
|
||||
assert(/Unhandled promise rejection/.test(warning.message));
|
||||
break;
|
||||
case 1:
|
||||
assert.strictEqual(warning.name, 'PromiseRejectionHandledWarning');
|
||||
assert(/Promise rejection was handled asynchronously/
|
||||
.test(warning.message));
|
||||
}
|
||||
}, 2));
|
||||
|
||||
const p = Promise.reject('This was rejected');
|
||||
setImmediate(common.mustCall(() => p.catch(() => {})));
|
Loading…
x
Reference in New Issue
Block a user