Skip to content

Commit da5b0ee

Browse files
committed
stream: reduce allocations on WHATWG streams hot paths
Pure-JavaScript optimizations to lib/internal/webstreams/* that reduce per-chunk and per-construction allocations on hot paths without observable behavior change. Per-chunk: reuse promise-reaction closures per controller, add buffered fast path for async iterator, specialize callback wrappers by arity, and share immutable nil records for writable stream resets. Per-construction: use queueMicrotask for non-object start results, materialize reader/writer .closed and .ready records lazily, and remove dead allocations. Assisted-by: Claude Fable 5 Signed-off-by: Matteo Collina <hello@matteocollina.com>
1 parent 19c46ab commit da5b0ee

5 files changed

Lines changed: 484 additions & 297 deletions

File tree

benchmark/webstreams/creation.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ const bench = common.createBenchmark(main, {
2121

2222
'ReadableStream.tee',
2323
],
24+
}, {
25+
// Each case collects garbage right before bench.start() so that the
26+
// timed window measures the work under test rather than leftover
27+
// GC work from the setup phase.
28+
flags: ['--expose-gc'],
2429
});
2530

2631
let readableStream;
@@ -33,6 +38,7 @@ let teeResult;
3338
function main({ n, kind }) {
3439
switch (kind) {
3540
case 'ReadableStream':
41+
globalThis.gc();
3642
bench.start();
3743
for (let i = 0; i < n; ++i)
3844
readableStream = new ReadableStream();
@@ -42,6 +48,7 @@ function main({ n, kind }) {
4248
assert.ok(readableStream);
4349
break;
4450
case 'WritableStream':
51+
globalThis.gc();
4552
bench.start();
4653
for (let i = 0; i < n; ++i)
4754
writableStream = new WritableStream();
@@ -51,6 +58,7 @@ function main({ n, kind }) {
5158
assert.ok(writableStream);
5259
break;
5360
case 'TransformStream':
61+
globalThis.gc();
5462
bench.start();
5563
for (let i = 0; i < n; ++i)
5664
transformStream = new TransformStream();
@@ -62,6 +70,7 @@ function main({ n, kind }) {
6270
case 'ReadableStreamDefaultReader': {
6371
const readers = Array.from({ length: n }, () => new ReadableStream());
6472

73+
globalThis.gc();
6574
bench.start();
6675
for (let i = 0; i < n; ++i)
6776
readableStreamDefaultReader = new ReadableStreamDefaultReader(readers[i]);
@@ -74,6 +83,7 @@ function main({ n, kind }) {
7483
case 'ReadableStreamBYOBReader': {
7584
const readers = Array.from({ length: n }, () => new ReadableStream({ type: 'bytes' }));
7685

86+
globalThis.gc();
7787
bench.start();
7888
for (let i = 0; i < n; ++i)
7989
readableStreamBYOBReader = new ReadableStreamBYOBReader(readers[i]);
@@ -86,6 +96,7 @@ function main({ n, kind }) {
8696
case 'ReadableStream.tee': {
8797
const streams = Array.from({ length: n }, () => new ReadableStream());
8898

99+
globalThis.gc();
89100
bench.start();
90101
for (let i = 0; i < n; ++i)
91102
teeResult = streams[i].tee();

0 commit comments

Comments
 (0)