Skip to content

Commit 56bc9ed

Browse files
committed
stream: improve performance of finished()
The changes optimize the end-of-stream.js module to only preserve AsyncLocalStorage context when it's actually needed, improving performance in the common case where no async context tracking is active.
1 parent 4984b15 commit 56bc9ed

File tree

2 files changed

+48
-2
lines changed

2 files changed

+48
-2
lines changed

benchmark/streams/end-of-stream.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const { Readable, Writable, Duplex, finished } = require('stream');
5+
6+
const bench = common.createBenchmark(main, {
7+
n: [1e5],
8+
streamType: ['readable', 'writable', 'duplex'],
9+
});
10+
11+
function main({ n, streamType }) {
12+
bench.start();
13+
14+
for (let i = 0; i < n; i++) {
15+
let stream;
16+
17+
switch (streamType) {
18+
case 'readable':
19+
stream = new Readable({ read() { this.push(null); } });
20+
break;
21+
case 'writable':
22+
stream = new Writable({ write(chunk, enc, cb) { cb(); } });
23+
stream.end();
24+
break;
25+
case 'duplex':
26+
stream = new Duplex({
27+
read() { this.push(null); },
28+
write(chunk, enc, cb) { cb(); },
29+
});
30+
stream.end();
31+
break;
32+
}
33+
34+
finished(stream, () => {});
35+
}
36+
37+
bench.end(n);
38+
}

lib/internal/streams/end-of-stream.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ const {
4444
kIsClosedPromise,
4545
} = require('internal/streams/utils');
4646

47+
const { getHookArrays } = require('internal/async_hooks');
48+
const AsyncContextFrame = require('internal/async_context_frame');
49+
4750
// Lazy load
4851
let AsyncLocalStorage;
4952
let addAbortListener;
@@ -66,8 +69,13 @@ function eos(stream, options, callback) {
6669
validateFunction(callback, 'callback');
6770
validateAbortSignal(options.signal, 'options.signal');
6871

69-
AsyncLocalStorage ??= require('async_hooks').AsyncLocalStorage;
70-
callback = once(AsyncLocalStorage.bind(callback));
72+
if (AsyncContextFrame.current() ||
73+
getHookArrays()[0].length > 0) {
74+
AsyncLocalStorage ??= require('async_hooks').AsyncLocalStorage;
75+
callback = once(AsyncLocalStorage.bind(callback));
76+
} else {
77+
callback = once(callback);
78+
}
7179

7280
if (isReadableStream(stream) || isWritableStream(stream)) {
7381
return eosWeb(stream, options, callback);

0 commit comments

Comments
 (0)