Skip to content

Commit 37d49f3

Browse files
gurgundayaduh95
authored andcommitted
process: optimize asyncHandledRejections by using FixedQueue
PR-URL: #60854 Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com> Reviewed-By: Ilyas Shabi <ilyasshabi94@gmail.com> Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
1 parent b39508b commit 37d49f3

2 files changed

Lines changed: 51 additions & 8 deletions

File tree

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
'use strict';
2+
3+
const common = require('../common.js');
4+
5+
// Benchmarks the throughput of processing many promise rejections that are
6+
// initially unhandled, get warned, and then handled asynchronously, exercising
7+
// asyncHandledRejections + processPromiseRejections.
8+
//
9+
// Note: This benchmark uses --unhandled-rejections=warn to avoid crashing
10+
// when promises are temporarily unhandled.
11+
12+
const bench = common.createBenchmark(main, {
13+
n: [1e4, 5e4, 1e5],
14+
}, {
15+
flags: ['--unhandled-rejections=warn'],
16+
});
17+
18+
function main({ n }) {
19+
const rejections = [];
20+
21+
// Suppress warning output during the benchmark
22+
process.removeAllListeners('warning');
23+
24+
for (let i = 0; i < n; i++) {
25+
rejections.push(Promise.reject(i));
26+
}
27+
28+
// Wait for them to be processed as unhandled and warned.
29+
setImmediate(() => {
30+
setImmediate(() => {
31+
bench.start();
32+
33+
for (let i = 0; i < n; i++) {
34+
rejections[i].catch(() => {});
35+
}
36+
37+
// Let processPromiseRejections drain asyncHandledRejections.
38+
setImmediate(() => {
39+
bench.end(n);
40+
});
41+
});
42+
});
43+
}

lib/internal/process/promises.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
'use strict';
22

33
const {
4-
ArrayPrototypePush,
5-
ArrayPrototypeShift,
64
Error,
75
ObjectPrototypeHasOwnProperty,
86
SafeMap,
97
SafeWeakMap,
108
} = primordials;
119

10+
const FixedQueue = require('internal/fixed_queue');
11+
1212
const {
1313
tickInfo,
1414
promiseRejectEvents: {
@@ -142,9 +142,9 @@ const maybeUnhandledPromises = new SafeWeakMap();
142142
let pendingUnhandledRejections = new SafeMap();
143143

144144
/**
145-
* @type {Array<{promise: Promise, warning: Error}>}
145+
* @type {import('internal/fixed_queue')<{promise: Promise, warning: Error}>}
146146
*/
147-
const asyncHandledRejections = [];
147+
const asyncHandledRejections = new FixedQueue();
148148

149149
/**
150150
* @type {number}
@@ -281,7 +281,7 @@ function handledRejection(promise) {
281281
if (promiseInfo.warned) {
282282
// Generate the warning object early to get a good stack trace.
283283
const warning = new PromiseRejectionHandledWarning(promiseInfo.uid);
284-
ArrayPrototypePush(asyncHandledRejections, { promise, warning });
284+
asyncHandledRejections.push({ promise, warning });
285285
setHasRejectionToWarn(true);
286286
}
287287
}
@@ -437,10 +437,10 @@ function getUnhandledRejectionsMode() {
437437
// a warning to be emitted which requires the microtask and next tick
438438
// queues to be drained again.
439439
function processPromiseRejections() {
440-
let maybeScheduledTicksOrMicrotasks = asyncHandledRejections.length > 0;
440+
let maybeScheduledTicksOrMicrotasks = !asyncHandledRejections.isEmpty();
441441

442-
while (asyncHandledRejections.length !== 0) {
443-
const { promise, warning } = ArrayPrototypeShift(asyncHandledRejections);
442+
while (!asyncHandledRejections.isEmpty()) {
443+
const { promise, warning } = asyncHandledRejections.shift();
444444
if (!process.emit('rejectionHandled', promise)) {
445445
process.emitWarning(warning);
446446
}

0 commit comments

Comments
 (0)