Skip to content

TransformStreams have an unforuntate design #1351

@BlackAsLight

Description

@BlackAsLight

What is the issue with the Streams Standard?

The design of TransformStreams are unfavourable when it comes to BYOB readable streams. I understand that it may be too late to change it, but nevertheless I'd like to express how they are so.

From the looks of it, TransformStreams were designed to be used in the .pipeThrough method available on ReadableStreams. They expose a Writable and a Readable stream for an input and output source, having the .pipeThrough method needlessly connect a Writable to a Readable.

From the looks of the purpose of a Readable and Writable Stream;

  • A Readable Stream is meant to provide resources on a pull schedule. I ask for more as I need it.
  • A Writable Stream is meant to provide resources on a push schedule. I receive more as you give it.

Connecting a push schedule to a pull schedule seems like a good way to end up with a big internal queue if the pulling is too slow.

But that's all really irrelevant since if you're making a TransformStream, you either use the transform(chunk, controller) method available on the constructor, or you create an internal transform stream to merely convert the writable to a readable.

class TransformSomething<I, O> implements TransformStream<I, O> {
  readable: ReadableStream<O>
  writable: WritableStream<I>
  constructor() {
    const { readable, writable } = new TransformStream<I, I>();
    this.readable = this.#process(readable);
    this.writable = writable;
  }

  #process(readable: ReadableStream<I>): ReadableStream<O> {
    throw new Error("Not Implemented");
  }
}

This is a waste of processing because all one wants to do when transforming a stream is consume one readable and spit out another.

But do you know why this is a bigger disappointment? Because one can't consume the readable as a byob stream. If the source for my TransformStream supported byob, I can't consume it as one, and my TransformStream might also support returning a byob stream, but it can't be consumed as one if another pipe operation is called afterwards.

The only way to get around this is to not offer a TransformStream and instead a function or class that asks specifically for a readable stream to be passed in before returning a readable stream of their own. Meaning we can't use the nice pipe methods. This is what's truly unfortunate. The fact that TransformStreams can't be byob.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions