Repository: nodejs/node
File: lib/internal/webstreams/readablestream.js (JavaScript)

Code before:
      return PromiseReject(
        new ERR_INVALID_STATE.TypeError(
          'The reader is not attached to a stream'));
    }
    const readRequest = new DefaultReadRequest();
    readableStreamDefaultReaderRead(this, readRequest);
    return readRequest.promise;
  }

  releaseLock() {
    if (!isReadableStreamDefaultReader(this))
      throw new ERR_INVALID_THIS('ReadableStreamDefaultReader');
    if (this[kState].stream === undefined)
      return;
    readableStreamDefaultReaderRelease(this);
  }

  /**
   * @readonly
   * @type {Promise<void>}
   */
  get closed() {
    if (!isReadableStreamDefaultReader(this))
      return PromiseReject(new ERR_INVALID_THIS('ReadableStreamDefaultReader'));
    return this[kState].close.promise;
  }

  /**
   * @param {any} [reason]
   * @returns {Promise<void>}
   */
  cancel(reason = undefined) {
    if (!isReadableStreamDefaultReader(this))
      return PromiseReject(new ERR_INVALID_THIS('ReadableStreamDefaultReader'));
    if (this[kState].stream === undefined) {
      return PromiseReject(new ERR_INVALID_STATE.TypeError(
        'The reader is not attached to a stream'));
    }
    return readableStreamReaderGenericCancel(this, reason);
  }

  [kInspect](depth, options) {
    return customInspect(depth, options, this[kType], {
      stream: this[kState].stream,
      readRequests: this[kState].readRequests.length,
      close: this[kState].close.promise,
    });
  }
}

ObjectDefineProperties(ReadableStreamDefaultReader.prototype, {

Review comment (performance):
It looks like the only difference between the fast and slow paths is that the fast path calls `PromiseResolve()` while the slow path [calls `[kChunk]`](https://github.com/mcollina/node/blob/76ccbaf50ca1ed7c61271976cbc414d3cfa9ad83/lib/internal/webstreams/readablestream.js#L2510) which calls [`PromiseWithResolvers().resolve()`](https://github.com/mcollina/node/blob/76ccbaf50ca1ed7c61271976cbc414d3cfa9ad83/lib/internal/webstreams/readablestream.js#L794). The rest of the code is just a copy-paste of [`readableStreamDefaultControllerPullSteps`](https://github.com/mcollina/node/blob/76ccbaf50ca1ed7c61271976cbc414d3cfa9ad83/lib/internal/webstreams/readablestream.js#L2502-L2512).

Comparing the specification for [PromiseResolve](https://tc39.es/ecma262/#sec-promise-resolve) and [Promise.withResolvers](https://tc39.es/ecma262/#sec-promise.withResolvers), they seem identical? The first calls `promiseCapability.[[Resolve]]` immediately, while the second exposes that same `promiseCapability.[[Resolve]]` as a function on the resulting `obj`. So there shouldn't be a difference in the number of microtasks: both resolve the promise immediately.

So where is the speed up coming from?

Code after:
      return PromiseReject(
        new ERR_INVALID_STATE.TypeError(
          'The reader is not attached to a stream'));
    }

    const stream = this[kState].stream;
    const controller = stream[kState].controller;

    // Fast path: if data is already buffered in a default controller,
    // return a resolved promise immediately without creating a read request.
    // This is spec-compliant because read() returns a Promise, and
    // Promise.resolve() callbacks still run in the microtask queue.
    if (stream[kState].state === 'readable' &&
        isReadableStreamDefaultController(controller) &&
        controller[kState].queue.length > 0) {
      stream[kState].disturbed = true;
      const chunk = dequeueValue(controller);

      if (controller[kState].closeRequested && !controller[kState].queue.length) {
        readableStreamDefaultControllerClearAlgorithms(controller);
        readableStreamClose(stream);
      } else {
        readableStreamDefaultControllerCallPullIfNeeded(controller);
      }

      return PromiseResolve({ value: chunk, done: false });
    }

    // Slow path: create request and go through normal flow
    const readRequest = new DefaultReadRequest();
    readableStreamDefaultReaderRead(this, readRequest);
    return readRequest.promise;
  }

  releaseLock() {
    if (!isReadableStreamDefaultReader(this))
      throw new ERR_INVALID_THIS('ReadableStreamDefaultReader');
    if (this[kState].stream === undefined)
      return;
    readableStreamDefaultReaderRelease(this);
  }

  /**
   * @readonly
   * @type {Promise<void>}
   */
  get closed() {
    if (!isReadableStreamDefaultReader(this))
      return PromiseReject(new ERR_INVALID_THIS('ReadableStreamDefaultReader'));
    return this[kState].close.promise;
  }