From 4960b6659c9cf305ae3578957e4d45419626c9b9 Mon Sep 17 00:00:00 2001 From: Marcos Casagrande <marcoscvp90@gmail.com> Date: Sun, 17 Sep 2023 17:54:40 +0200 Subject: [PATCH] perf(ext/streams): optimize async iterator (#20541) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR optimizes `ReadableStream` async iterator ### Benchmarks ```js Deno.bench("Stream - iterator", async () => { const stream = new ReadableStream({ start(controller) { controller.enqueue(new Uint8Array([97])); controller.enqueue(new Uint8Array([97])); controller.close(); }, }); for await (const chunk of stream) {} }); ``` **main** `2 chunks` ``` cpu: 13th Gen Intel(R) Core(TM) i9-13900H runtime: deno 1.36.4 (x86_64-unknown-linux-gnu) benchmark time (avg) iter/s (min … max) p75 p99 p995 ----------------------------------------------------------------------- ----------------------------- Stream - iterator 12.45 µs/iter 80,295.5 (10.5 µs … 281.12 µs) 12.13 µs 26.71 µs 33.63 µs ``` `20 chunks` ``` benchmark time (avg) iter/s (min … max) p75 p99 p995 ----------------------------------------------------------------------- ----------------------------- Stream - iterator 32.99 µs/iter 30,312.2 (28.13 µs … 1.21 ms) 31.8 µs 81.82 µs 179.93 µs ``` --- **this PR** `2 chunks` ``` cpu: 13th Gen Intel(R) Core(TM) i9-13900H runtime: deno 1.36.4 (x86_64-unknown-linux-gnu) benchmark time (avg) iter/s (min … max) p75 p99 p995 ----------------------------------------------------------------------- ----------------------------- Stream - iterator 9.37 µs/iter 106,700.8 (8.35 µs … 730.71 µs) 9.15 µs 13.12 µs 18.17 µs ``` `20 chunks` ``` benchmark time (avg) iter/s (min … max) p75 p99 p995 ----------------------------------------------------------------------- ----------------------------- Stream - iterator 16.59 µs/iter 60,270.0 (12.08 µs … 1.37 ms) 15.06 µs 83.03 µs 123.52 µs ``` --- ext/web/06_streams.js | 38 ++++++++------------------------------ 1 file changed, 8 insertions(+), 30 deletions(-) diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index 0f59546726..6d2a552320 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -53,10 +53,8 @@ const { NumberIsInteger, NumberIsNaN, ObjectCreate, - ObjectDefineProperties, ObjectDefineProperty, ObjectGetPrototypeOf, - ObjectPrototype, ObjectPrototypeIsPrototypeOf, ObjectSetPrototypeOf, Promise, @@ -4651,26 +4649,6 @@ function writableStreamUpdateBackpressure(stream, backpressure) { stream[_backpressure] = backpressure; } -/** - * @template T - * @param {T} value - * @param {boolean} done - * @returns {IteratorResult<T>} - */ -function createIteratorResult(value, done) { - const result = ObjectCreate(ObjectPrototype); - ObjectDefineProperties(result, { - value: { value, writable: true, enumerable: true, configurable: true }, - done: { - value: done, - writable: true, - enumerable: true, - configurable: true, - }, - }); - return result; -} - /** @type {AsyncIterator<unknown, unknown>} */ const asyncIteratorPrototype = ObjectGetPrototypeOf(AsyncGeneratorPrototype); @@ -4685,7 +4663,7 @@ const readableStreamAsyncIteratorPrototype = ObjectSetPrototypeOf({ const reader = this[_reader]; function nextSteps() { if (reader[_iteratorFinished]) { - return PromiseResolve(createIteratorResult(undefined, true)); + return PromiseResolve({ value: undefined, done: true }); } if (reader[_stream] === undefined) { @@ -4701,11 +4679,11 @@ const readableStreamAsyncIteratorPrototype = ObjectSetPrototypeOf({ /** @type {ReadRequest} */ const readRequest = { chunkSteps(chunk) { - promise.resolve(createIteratorResult(chunk, false)); + promise.resolve({ value: chunk, done: false }); }, closeSteps() { readableStreamDefaultReaderRelease(reader); - promise.resolve(createIteratorResult(undefined, true)); + promise.resolve({ value: undefined, done: true }); }, errorSteps(e) { readableStreamDefaultReaderRelease(reader); @@ -4718,7 +4696,7 @@ const readableStreamAsyncIteratorPrototype = ObjectSetPrototypeOf({ reader[_iteratorNext] = null; if (result.done === true) { reader[_iteratorFinished] = true; - return createIteratorResult(undefined, true); + return { value: undefined, done: true }; } return result; }, (reason) => { @@ -4743,12 +4721,12 @@ const readableStreamAsyncIteratorPrototype = ObjectSetPrototypeOf({ const reader = this[_reader]; const returnSteps = () => { if (reader[_iteratorFinished]) { - return PromiseResolve(createIteratorResult(arg, true)); + return PromiseResolve({ value: arg, done: true }); } reader[_iteratorFinished] = true; if (reader[_stream] === undefined) { - return PromiseResolve(createIteratorResult(undefined, true)); + return PromiseResolve({ value: undefined, done: true }); } assert(reader[_readRequests].length === 0); if (this[_preventCancel] === false) { @@ -4757,7 +4735,7 @@ const readableStreamAsyncIteratorPrototype = ObjectSetPrototypeOf({ return result; } readableStreamDefaultReaderRelease(reader); - return PromiseResolve(createIteratorResult(undefined, true)); + return PromiseResolve({ value: undefined, done: true }); }; const returnPromise = reader[_iteratorNext] @@ -4765,7 +4743,7 @@ const readableStreamAsyncIteratorPrototype = ObjectSetPrototypeOf({ : returnSteps(); return PromisePrototypeThen( returnPromise, - () => createIteratorResult(arg, true), + () => ({ value: arg, done: true }), ); }, }, asyncIteratorPrototype);