Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

welp, looking for that readableStream iterator polyfill #128

Closed
jimmywarting opened this issue Aug 31, 2023 · 7 comments
Closed

welp, looking for that readableStream iterator polyfill #128

jimmywarting opened this issue Aug 31, 2023 · 7 comments

Comments

@jimmywarting
Copy link

I remember somebody asking how to take a ReadableStream and turning it into a asyncIterator.
I came with a suggestion and then you added some improvements to it.

Don't remember where it was...
that person posted it somewhere in your repos i think...

@MattiasBuelens
Copy link
Owner

I should really have put that in a Gist...

Did you manage to find it again? I can't seem to find it myself. 😅

@jimmywarting
Copy link
Author

jimmywarting commented Aug 31, 2023

I should really have put that in a Gist...

dito

Did you manage to find it again?

nope, maybe i have to rewrite it. but i don't remember what your suggestions where to make it more spec compatible.

All i can say is that it started with ReadableStream.prototype[Symbol.asyncIterator] ??= 😅

Gona try searching my computer for it.

@jimmywarting
Copy link
Author

found this in one readme file.

import 'fast-readable-async-iterator'

// or

if (typeof ReadableStream !== 'undefined' && !ReadableStream.prototype[Symbol.asyncIterator]) {
  ReadableStream.prototype[Symbol.asyncIterator] = function () {
    const reader = this.getReader()
    let last = reader.read()
    return {
      next () {
        const temp = last
        last = reader.read()
        return temp
      },
      return () {
        return reader.releaseLock()
      },
      throw (err) {
        this.return()
        throw err
      },
      [Symbol.asyncIterator] () {
        return this
      }
    }
  }
}

And also this one:

ReadableStream.prototype[Symbol.asyncIterator] ??= function () {
  const reader = this.getReader()
  return {
    next: _ => reader.read(),
    return: _ => { reader.releaseLock() },
    throw: err => {
      this.return()
      throw err
    },
    [Symbol.asyncIterator] () {
      return this
    }
  }
}

@MattiasBuelens
Copy link
Owner

MattiasBuelens commented Sep 1, 2023

Yeah, but those are still quite different from the specced behavior.

I would recommend something like this:

ReadableStream.prototype.values ??= function({ preventCancel = false } = {}) {
    const reader = this.getReader();
    return {
        async next() {
            try {
                const result = await reader.read();
                if (result.done) {
                    reader.releaseLock();
                }
                return result;
            } catch (e) {
                reader.releaseLock();
                throw e;
            }
        },
        async return(value) {
            if (!preventCancel) {
                const cancelPromise = reader.cancel(value);
                reader.releaseLock();
                await cancelPromise;
            } else {
                reader.releaseLock();
            }
            return { done: true, value };
        },
        [Symbol.asyncIterator]() {
            return this;
        }
    };
};

ReadableStream.prototype[Symbol.asyncIterator] ??= ReadableStream.prototype.values;

Now also as a Gist! 😁

@jimmywarting
Copy link
Author

Thanks yet again for recreating the recommendations.

@jimmywarting
Copy link
Author

jimmywarting commented Sep 4, 2023

You know... with this in place combined with a polyfill for ReadableStream.from(iterable) then this would make it a grate solution for converting your polyfilled ReadableStream instance into a native ReadableStream instance that could be transfered with postMessage.

import { ReadableStream as Polyfill } from 'pkg'

var native = globalThis.ReadableStream.from(new Polyfill(...))
// and it would work the same the other way around
var polyfill = Polyfill.from(new globalThis.ReadableStream(...))

it would make the web-streams-adapter a bit obsolete.

kind of solves the conversion between node:streams to web streams as well when having a polyfill for .from() as well.

Perhaps dose not cover all the bits and pieces such as sink and BYOB reader and other stuff (?). But could get the job done for most stuff.

@MattiasBuelens
Copy link
Owner

Yes, that was deliberate, see whatwg/streams#1083 (comment). 😁

I really need to find some time to work on web-streams-polyfill again and add ReadableStream.from(). Converting from a native ReadableStream or a Node.js Readable has always been painful with the polyfill (even when you use web-streams-adapter), and from() would help a lot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants