Add internal fast paths to improve webstreams performance without changing the public API or breaking spec compliance. 1. ReadableStreamDefaultReader.read() fast path: When data is already buffered in the controller's queue, return PromiseResolve() directly without creating a DefaultReadRequest object. This is spec-compliant because read() returns a Promise, and resolved promises still run callbacks in the microtask queue. 2. pipeTo() batch read fast path: When data is buffered, batch reads directly from the controller queue up to highWaterMark without creating PipeToReadableStreamReadRequest objects per chunk. Respects backpressure by checking desiredSize after each write. Benchmark results: - pipeTo: ~11% faster (***) - buffered read(): ~17-20% faster (***) Co-Authored-By: Malte Ubl <malte@vercel.com> PR-URL: https://github.com/nodejs/node/pull/61807 Reviewed-By: Stephen Belanger <admin@stephenbelanger.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day> Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
54 lines
1.3 KiB
JavaScript
54 lines
1.3 KiB
JavaScript
'use strict';
|
|
const common = require('../common.js');
|
|
const { ReadableStream } = require('node:stream/web');
|
|
|
|
// Benchmark for reading from a pre-buffered ReadableStream.
|
|
// This measures the fast path optimization where data is already
|
|
// queued in the controller, avoiding DefaultReadRequest allocation.
|
|
|
|
const bench = common.createBenchmark(main, {
|
|
n: [1e5],
|
|
bufferSize: [1, 10, 100, 1000],
|
|
});
|
|
|
|
async function main({ n, bufferSize }) {
|
|
let enqueued = 0;
|
|
|
|
const rs = new ReadableStream({
|
|
start(controller) {
|
|
// Pre-fill the buffer
|
|
for (let i = 0; i < bufferSize; i++) {
|
|
controller.enqueue('a');
|
|
enqueued++;
|
|
}
|
|
},
|
|
pull(controller) {
|
|
// Refill buffer when pulled
|
|
const toEnqueue = Math.min(bufferSize, n - enqueued);
|
|
for (let i = 0; i < toEnqueue; i++) {
|
|
controller.enqueue('a');
|
|
enqueued++;
|
|
}
|
|
if (enqueued >= n) {
|
|
controller.close();
|
|
}
|
|
},
|
|
}, {
|
|
// Use buffer size as high water mark to allow pre-buffering
|
|
highWaterMark: bufferSize,
|
|
});
|
|
|
|
const reader = rs.getReader();
|
|
let x = null;
|
|
let reads = 0;
|
|
|
|
bench.start();
|
|
while (reads < n) {
|
|
const { value, done } = await reader.read();
|
|
if (done) break;
|
|
x = value;
|
|
reads++;
|
|
}
|
|
bench.end(reads);
|
|
console.assert(x);
|
|
}
|