whatwg / streams

Streams Standard
https://streams.spec.whatwg.org/
Other
1.34k stars 155 forks source link

Proposal: BodyReader for ReadableStream #1308

Closed jasnell closed 3 months ago

jasnell commented 3 months ago

What problem are you trying to solve?

It is very common to consume a ReadableStream into a text, TypedArray, Blob, etc. In the fetch spec, there is the Body structure that exposes methods like text(), json(), blob(), etc for efficiently consuming the Request or Response payload. Unfortunately, for other types of ReadableStreams it's not so efficient and generally requires a fair amount of boilerplate. It would be nice to simplify.

async function text(readable) {
  let text = '';
  const dec = new TextDecoder();
  for await (const chunk of readable) {
    text += dec.decode(chunk, { stream: true });
  }
  text += dec.decode();
  return text;
}

What solutions exist today?

The Response and Request objects have methods like async text(), async json(), etc ...

Node.js has a require('stream/adapters') API that implements these methods for ReadableStream and Node.js streams.

How would you solve it?

This proposal is to introduce a new ReadableStreamBodyReader to the streams spec with the definition. Like ReaableStreamBYOBReader, the ReadableStreamBodyReader would only be used with bytes type streams.

[Exposed=*]
interface ReadableStreamBodyReader {
  constructor(ReadableStream);

  Promise<ArrayBuffer> arrayBuffer();
  Promise<Blob> blob();
  Promise<FormData> formData();
  Promise<any> json();
  Promise<USVString> text();

  undefined releaseLock();
};
ReadableStreamBodyReader includes ReadableStreamGenericReader;

Example use:

const readable = new ReadableStream({ type: 'bytes', /* ... */ });
const reader = new ReadableStreamBodyReader(readable);
// or 
const reader = readable.getReader({ mode: 'body' });
await text = reader.text();

// With decoding...
const source = new ReadableStream({ type: 'bytes', /* ... */ });
const readable = source.pipeThrough(new TextDecoderStream());
const reader = new ReadableStreamBodyReader(readable);
await text = reader.text();

This model would allow implementations to optimize the read operation internally as much as possible and eliminate a fair amount of boilerplate.

Anything else?

No response

domenic commented 3 months ago

Dupe of #1238.

jasnell commented 3 months ago

Ha! I had completely forgotten that I had opened that previous issue. Sigh.