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);