Skip to content

Cancelling and exception handling async iteration of ReadableStreams #1255

@hamishwillee

Description

@hamishwillee

I'm looking at this for the MDN documentation (tracked in mdn/content#23678)

Reading a stream looks pretty straightforward; you get a stream and read it in chunks using for await (const chunk of mystream) {}:

let bytes = 0;
logChunks(mystream);
async function logChunks(readableXX) {
  for await (const chunk of readableXX) {
    bytes+=chunk.length;
    logConsumer( `Chunk: ${chunk}. Read ${bytes} characters.`);
  }
}
  1. What is the "right way" to cancel a stream read during async iteration from a button press?

    If you're writing your own underlying source then you can add a listener that closes the stream on button click using controller.close().

    return new ReadableStream({
        start(controller) {
        button.addEventListener('click', () => {
          controller.close();
          });
        readRepeatedly().catch((e) => controller.error(e));
        ...

    But if you're using fetch() you have no control over the underlying source - you get a ReadableStream back from the response.

    • you can't call cancel on the stream because it is locked to the default reader, for which you don't have a handle (since you're working direct with the readablestream).
    • You could set a boolean in the event handler, then in the for loop you could use it to return, cancelling the operation. But this would have to await at least one more chunk, which could in theory take some time to arrive.
    • My guess is that for fetch you'd use an AbortController and abort the source of the stream. This would then propagate errors or whatever through the returned ReadableStream?

    What is the "general recommendation"? Is it that you abort the underlying source (if possible) and if not, perhaps you wrap your stream in a another custom stream?

  2. How are you supposed to handle errors from the source - e.g. a TypeError or a network error or something? I tried putting try/catch around the logChunks() above and various other places but I don't seem to be able to catch them.

  3. What is the recommended way to handle the case of a browser that does not support this feature? Is there a polyfill on the Internet that we should point users to?

  4. Tracking bugs seem to indicate this is not yet in Safari or Chrome. Do you happen to know if Deno/NodeJS support this, and if so, whether it is compatible to the streams spec?

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