Skip to content

Revisiting ReadableStream.from(syncIter) and ReadableStream.from(str) #1376

Description

@jasnell

What is the issue with the Streams Standard?

I know this has been discussed a number of times before but I would very much appreciate if we could revisit whether passing a sync iterable, string/single value to a ReadableStream.from would be possible.

Specifically, in reviewing real world code, it's become evident that the following is actually a fairly common usage pattern as awful as it is:

const rs = new ReadableStream({
  start(controller) {
    controller.enqueue(aSingleChunkOfSomething);
    controller.close();
  }
});

Then using the ReadableStream as part of a component in a larger rendering pipeline. The fundamental issue with this is that it's actually fairly difficult to optimize around since we are forced to allocate the controller, handle the start call and resulting microtask, etc.

It's also fairly common to seed a ReadableStream with an existing in memory data source like an array:

const chunks = [1,2,3];
const rs = new ReadableStream({
  pull(controller) {
    let chunk = chunks.shift();
    if (chunk !== undefined) {
      controller.enqueue(chunk);
    } else {
      controller.close();
    }
  }
});

We could provide more optimizations internally for cases like this by allowing ReadableStream.from(...) to accept a single value and/or sync iterator... Passing a string or BufferSource as a single value would special case in that they would not be treated as sync iterators:

ReadableStream.from('hello');  // yields only a single string 'hello' then closes
ReadableStream.from(new Uint8Array(10));  // yields only the single Uint8Array
ReadableStream.from([1,2,3]);  // yields 1, 2, then 3, then closes

This eliminates a significant amount of boilerplate and gives an opportunity to optimize by avoiding allocation of the underlying controller and not having to worry about user code grabbing and retaining a reference to the controller. It also means avoiding having to call out to the start and pull algorithms and the associated mechanism around it. The fact that it is more ergonomic for users is just another benefit.

/cc @MattiasBuelens @lucacasonato

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    addition/proposalNew features or enhancementsneeds implementer interestMoving the issue forward requires implementers to express interest

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions