Skip to content

Commit 832efd8

Browse files
committed
lib: reuse default DOMException in AbortController
Refs: #46086 Refs: nodejs/performance#44
1 parent 351bf77 commit 832efd8

File tree

2 files changed

+43
-3
lines changed

2 files changed

+43
-3
lines changed
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
'use strict';
2+
const common = require('../common.js');
3+
4+
const bench = common.createBenchmark(main, {
5+
n: [1e6],
6+
});
7+
8+
function main({ n }) {
9+
bench.start();
10+
for (let i = 0; i < n; i++) {
11+
const ac = new AbortController();
12+
ac.signal.addEventListener('abort', () => {});
13+
ac.abort();
14+
}
15+
bench.end(n);
16+
}

lib/internal/abort_controller.js

+27-3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const {
3030
customInspectSymbol,
3131
kEmptyObject,
3232
kEnumerableProperty,
33+
SideEffectFreeRegExpPrototypeSymbolReplace,
3334
} = require('internal/util');
3435
const { inspect } = require('internal/util/inspect');
3536
const {
@@ -63,11 +64,14 @@ const {
6364

6465
let _MessageChannel;
6566
let makeTransferable;
67+
let defaultDOMException;
6668

6769
// Loading the MessageChannel and makeTransferable have to be done lazily
6870
// because otherwise we'll end up with a require cycle that ends up with
6971
// an incomplete initialization of abort_controller.
7072

73+
const userModuleRegExp = /^ {4}at (?:[^/\\(]+ \()(?!node:(.+):\d+:\d+\)$).*/gm;
74+
7175
function lazyMessageChannel() {
7276
_MessageChannel ??= require('internal/worker/io').MessageChannel;
7377
return new _MessageChannel();
@@ -79,6 +83,21 @@ function lazyMakeTransferable(obj) {
7983
return makeTransferable(obj);
8084
}
8185

86+
function lazyDOMException() {
87+
if (defaultDOMException) {
88+
return defaultDOMException;
89+
}
90+
91+
defaultDOMException = new DOMException('This operation was aborted', 'AbortError');
92+
93+
// Avoid V8 leak and remove userland stackstrace
94+
defaultDOMException.stack = SideEffectFreeRegExpPrototypeSymbolReplace(
95+
userModuleRegExp,
96+
defaultDOMException.stack,
97+
'');
98+
return defaultDOMException;
99+
}
100+
82101
const clearTimeoutRegistry = new SafeFinalizationRegistry(clearTimeout);
83102
const timeOutSignals = new SafeSet();
84103

@@ -166,8 +185,10 @@ class AbortSignal extends EventTarget {
166185
* @param {any} [reason]
167186
* @returns {AbortSignal}
168187
*/
169-
static abort(
170-
reason = new DOMException('This operation was aborted', 'AbortError')) {
188+
static abort(reason) {
189+
if (reason === undefined) {
190+
reason = lazyDOMException();
191+
}
171192
return createAbortSignal({ aborted: true, reason });
172193
}
173194

@@ -328,7 +349,10 @@ class AbortController {
328349
/**
329350
* @param {any} [reason]
330351
*/
331-
abort(reason = new DOMException('This operation was aborted', 'AbortError')) {
352+
abort(reason) {
353+
if (reason === undefined) {
354+
reason = lazyDOMException();
355+
}
332356
abortSignal(this.#signal ??= createAbortSignal(), reason);
333357
}
334358

0 commit comments

Comments
 (0)