diff --git a/lib/internal/process/promises.js b/lib/internal/process/promises.js index f2145d425c620f..615ec7c398eff9 100644 --- a/lib/internal/process/promises.js +++ b/lib/internal/process/promises.js @@ -4,6 +4,7 @@ const { Error, ObjectDefineProperty, WeakMap, + Map, } = primordials; const { @@ -26,7 +27,7 @@ const { const kHasRejectionToWarn = 1; const maybeUnhandledPromises = new WeakMap(); -const pendingUnhandledRejections = []; +let pendingUnhandledRejections = new Map(); const asyncHandledRejections = []; let lastPromiseId = 0; @@ -119,32 +120,33 @@ function resolveError(type, promise, reason) { } function unhandledRejection(promise, reason) { - maybeUnhandledPromises.set(promise, { + const uid = ++lastPromiseId; + // This causes the promise to be referenced at least for one tick. + pendingUnhandledRejections.set(promise, { reason, - uid: ++lastPromiseId, - warned: false + uid }); - // This causes the promise to be referenced at least for one tick. - pendingUnhandledRejections.push(promise); setHasRejectionToWarn(true); } function handledRejection(promise) { + if (pendingUnhandledRejections.has(promise)) { + pendingUnhandledRejections.delete(promise); + return; + } const promiseInfo = maybeUnhandledPromises.get(promise); if (promiseInfo !== undefined) { maybeUnhandledPromises.delete(promise); - if (promiseInfo.warned) { - const { uid } = promiseInfo; - // Generate the warning object early to get a good stack trace. - // eslint-disable-next-line no-restricted-syntax - const warning = new Error('Promise rejection was handled ' + - `asynchronously (rejection id: ${uid})`); - warning.name = 'PromiseRejectionHandledWarning'; - warning.id = uid; - asyncHandledRejections.push({ promise, warning }); - setHasRejectionToWarn(true); - return; - } + const { uid } = promiseInfo; + // Generate the warning object early to get a good stack trace. + // eslint-disable-next-line no-restricted-syntax + const warning = new Error('Promise rejection was handled ' + + `asynchronously (rejection id: ${uid})`); + warning.name = 'PromiseRejectionHandledWarning'; + warning.id = uid; + asyncHandledRejections.push({ promise, warning }); + setHasRejectionToWarn(true); + return; } if (maybeUnhandledPromises.size === 0 && asyncHandledRejections.length === 0) setHasRejectionToWarn(false); @@ -197,14 +199,11 @@ function processPromiseRejections() { } } - let len = pendingUnhandledRejections.length; - while (len--) { - const promise = pendingUnhandledRejections.shift(); - const promiseInfo = maybeUnhandledPromises.get(promise); - if (promiseInfo === undefined) { - continue; - } - promiseInfo.warned = true; + const pending = pendingUnhandledRejections; + pendingUnhandledRejections = new Map(); + for (const [promise, promiseInfo] of pending.entries()) { + pending.delete(promise); + maybeUnhandledPromises.set(promise, promiseInfo); const { reason, uid } = promiseInfo; switch (unhandledRejectionsMode) { case kStrictUnhandledRejections: { @@ -256,7 +255,7 @@ function processPromiseRejections() { maybeScheduledTicksOrMicrotasks = true; } return maybeScheduledTicksOrMicrotasks || - pendingUnhandledRejections.length !== 0; + pendingUnhandledRejections.size !== 0; } function getErrorWithoutStack(name, message) {