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

Add @@asyncIterator to ReadableStream #980

Merged
merged 18 commits into from
Feb 6, 2019

Conversation

MattiasBuelens
Copy link
Collaborator

@MattiasBuelens MattiasBuelens commented Jan 26, 2019

This PR supersedes #954. So far, I've simply rebased @devsnek's changes onto master and fixed any conflicts.

WPT PR: web-platform-tests/wpt#15097

Closes #778


Preview | Diff

@MattiasBuelens
Copy link
Collaborator Author

The WPT submodule hasn't yet been updated, so the tests are currently failing on Travis because of the "unexpected" getIterator method.

The reference implementation passes all of the new tests locally. Even the dreaded Object.prototype check works correctly with the new test runner setup! 😄

@MattiasBuelens
Copy link
Collaborator Author

MattiasBuelens commented Jan 27, 2019

The tests have found a bug in the spec! 🎉

This test fails with the current reference implementation. When calling s.getReader(), the stream is still locked to the iterator's reader.

The problem is that it.return() is not called whenever a for await..of loop completes normally (i.e. when it.next() resolves with {done: true}). A quick snippet to demonstrate:

function testIterator() {
  return {
    [Symbol.asyncIterator]() {
      return {
        async next() {
          console.log('next() called');
          return {done: true};
        },
        async return() {
          console.log('return() called');
        }
      };
    }
  };
}

(async () => {
  console.log('before');
  for await (const chunk of testIterator()) {
    console.log({chunk});
  }
  console.log('after');
})();

This logs:

before
next() called
after

Clearly, the return() method was not called.

To fix this, we need to change the next() method to release the reader just before returning {done: true}. For example, we could change this line in the reference implementation to the following:

    return ReadableStreamDefaultReaderRead(reader)
      .then(({ value, done }) => {
        if (done) {
          ReadableStreamReaderGenericRelease(reader);
        }
        return ReadableStreamCreateReadResult(value, done);
      });

Or we could re-use the read result (although I don't know if this can cause issues?) to avoid creating an extra object:

    return ReadableStreamDefaultReaderRead(reader, true)
      .then(result => {
        if (result.done) {
          ReadableStreamReaderGenericRelease(reader);
        }
        return result;
      });

Similarly, the spec text should be updated to transform the returned promise with a fulfillment handler.

@domenic @ricea @devsnek Thoughts?

@domenic
Copy link
Member

domenic commented Jan 27, 2019

Yep, agreed, we should fix that! This was my second point in #778 (comment) .

@MattiasBuelens
Copy link
Collaborator Author

MattiasBuelens commented Jan 29, 2019

Yep, agreed, we should fix that! This was my second point in #778 (comment) .

All right, I'll fix it.

Any preference on the style of the .then handler? The only other example where ReadableStreamDefaultReaderRead is used internally in the spec is in step 12 of ReadableStreamTee, where the {done, value} tuple is explicitly destructured and asserted before it's used. Do we need to do the same thing here? For example:

  1. Return the result of transforming ! ReadableStreamDefaultReaderRead(reader) with a fulfillment handler which takes the argument result and performs the following steps:
    1. Assert: Type(result) is Object.
    2. Let value be ? Get(result, "value").
    3. Let done be ? Get(result, "done").
    4. Assert: Type(done) is Boolean.
    5. If done is true, perform ! ReadableStreamReaderGenericRelease(reader).
    6. Return ! ReadableStreamCreateReadResult(value, done, true).

Can we just check result.done directly and pass result along as-is (with Object.prototype already in its prototype chain)? Or could that cause issues?

  1. Return the result of transforming ! ReadableStreamDefaultReaderRead(reader, true) with a fulfillment handler which takes the argument result and performs the following steps:
    1. Let done be ? Get(result, "done").
    2. If done is true, perform ! ReadableStreamReaderGenericRelease(reader).
    3. Return result.

@ricea
Copy link
Collaborator

ricea commented Jan 29, 2019

Any preference on the style of the .then handler? The only other example where ReadableStreamDefaultReaderRead is used internally in the spec is in step 12 of ReadableStreamTee, where the {done, value} tuple is explicitly destructured and asserted before it's used. Do we need to do the same thing here?

I think we have to do it the long way. It would be weird if next() executed Object.prototype.then internally.

index.bs Outdated Show resolved Hide resolved
index.bs Outdated Show resolved Hide resolved
@MattiasBuelens
Copy link
Collaborator Author

I've pushed a commit to update WPT to the latest commit of the opened WPT PR, to check whether the new tests also pass on Travis. Once the WPT PR lands, I'll amend the commit to point to the merged commit in WPT.

@MattiasBuelens
Copy link
Collaborator Author

MattiasBuelens commented Feb 3, 2019

Aaaand the build fails on linter errors. Probably because I had to update eslint to support async function*() {}. But hey, at least npm run wpt succeeded! 😅

I'll see if the linter config can be updated to better match our coding style. If not, I guess I can just eslint --fix and commit. 😛

@MattiasBuelens
Copy link
Collaborator Author

And now it's bikeshed not knowing how to auto-link [@@asyncIterator]()... 🤦‍♂️

@domenic
Copy link
Member

domenic commented Feb 5, 2019

LGTM! Will let @ricea do the honors for merging tests and then spec. Thanks so much, @MattiasBuelens and @devsnek!

ricea pushed a commit to web-platform-tests/wpt that referenced this pull request Feb 6, 2019
Test async iteration of ReadableStream.

Standard changes are in whatwg/streams#980.
@ricea ricea merged commit bf2cac8 into whatwg:master Feb 6, 2019
@MattiasBuelens MattiasBuelens deleted the readablestream-asynciterator branch February 6, 2019 09:49
moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this pull request Feb 21, 2019
Automatic update from web-platform-tests
ReadableStream @@asyncIterator (#15097)

Test async iteration of ReadableStream.

Standard changes are in whatwg/streams#980.
--

wpt-commits: de6f8fcf9b87e80811e9267a886cf891f6f864e0
wpt-pr: 15097
mykmelez pushed a commit to mykmelez/gecko that referenced this pull request Feb 22, 2019
Automatic update from web-platform-tests
ReadableStream @@asyncIterator (#15097)

Test async iteration of ReadableStream.

Standard changes are in whatwg/streams#980.
--

wpt-commits: de6f8fcf9b87e80811e9267a886cf891f6f864e0
wpt-pr: 15097
moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this pull request Feb 26, 2019
Automatic update from web-platform-tests
ReadableStream @@asyncIterator (#15097)

Test async iteration of ReadableStream.

Standard changes are in whatwg/streams#980.
--

wpt-commits: de6f8fcf9b87e80811e9267a886cf891f6f864e0
wpt-pr: 15097
mykmelez pushed a commit to mykmelez/gecko that referenced this pull request Feb 27, 2019
Automatic update from web-platform-tests
ReadableStream @@asyncIterator (#15097)

Test async iteration of ReadableStream.

Standard changes are in whatwg/streams#980.
--

wpt-commits: de6f8fcf9b87e80811e9267a886cf891f6f864e0
wpt-pr: 15097
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified that referenced this pull request Oct 3, 2019
Automatic update from web-platform-tests
ReadableStream asyncIterator (#15097)

Test async iteration of ReadableStream.

Standard changes are in whatwg/streams#980.
--

wpt-commits: de6f8fcf9b87e80811e9267a886cf891f6f864e0
wpt-pr: 15097

UltraBlame original commit: a3f2954c055c5c09fb25ea019b6efc555fcd127c
gecko-dev-updater pushed a commit to marco-c/gecko-dev-comments-removed that referenced this pull request Oct 4, 2019
Automatic update from web-platform-tests
ReadableStream asyncIterator (#15097)

Test async iteration of ReadableStream.

Standard changes are in whatwg/streams#980.
--

wpt-commits: de6f8fcf9b87e80811e9267a886cf891f6f864e0
wpt-pr: 15097

UltraBlame original commit: a3f2954c055c5c09fb25ea019b6efc555fcd127c
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified that referenced this pull request Oct 4, 2019
Automatic update from web-platform-tests
ReadableStream asyncIterator (#15097)

Test async iteration of ReadableStream.

Standard changes are in whatwg/streams#980.
--

wpt-commits: de6f8fcf9b87e80811e9267a886cf891f6f864e0
wpt-pr: 15097

UltraBlame original commit: daffa4526e1850355356d0131230159b9eed8724
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified-and-comments-removed that referenced this pull request Oct 4, 2019
Automatic update from web-platform-tests
ReadableStream asyncIterator (#15097)

Test async iteration of ReadableStream.

Standard changes are in whatwg/streams#980.
--

wpt-commits: de6f8fcf9b87e80811e9267a886cf891f6f864e0
wpt-pr: 15097

UltraBlame original commit: a3f2954c055c5c09fb25ea019b6efc555fcd127c
gecko-dev-updater pushed a commit to marco-c/gecko-dev-comments-removed that referenced this pull request Oct 4, 2019
Automatic update from web-platform-tests
ReadableStream asyncIterator (#15097)

Test async iteration of ReadableStream.

Standard changes are in whatwg/streams#980.
--

wpt-commits: de6f8fcf9b87e80811e9267a886cf891f6f864e0
wpt-pr: 15097

UltraBlame original commit: daffa4526e1850355356d0131230159b9eed8724
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified-and-comments-removed that referenced this pull request Oct 4, 2019
Automatic update from web-platform-tests
ReadableStream asyncIterator (#15097)

Test async iteration of ReadableStream.

Standard changes are in whatwg/streams#980.
--

wpt-commits: de6f8fcf9b87e80811e9267a886cf891f6f864e0
wpt-pr: 15097

UltraBlame original commit: daffa4526e1850355356d0131230159b9eed8724
@zizifn
Copy link

zizifn commented Jun 23, 2022

Sorry for create noise here, does anyone know timeline for browers plan to support this?

@MattiasBuelens
Copy link
Collaborator Author

Sorry for create noise here, does anyone know timeline for browers plan to support this?

We've filed implementation bugs with all major browser vendors, see #778 (comment). From there, it's up to each individual browser vendor to implement this change as they see fit.

You can star the Chromium issue and/or vote on the Firefox bug in order to let them know that you're interested in this feature. Or, if you're willing to put in the effort, you can contribute an implementation yourself. 😉 (Do post a comment on the bug first to inform them that you're working on it though, so they don't end up doing duplicate work.)

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

Successfully merging this pull request may close these issues.

ReadableStream should be an async iterable
5 participants