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

Update ongoing promise in async iterator return() method #1387

Merged

Conversation

MattiasBuelens
Copy link
Contributor

@MattiasBuelens MattiasBuelens commented Feb 7, 2024

@yuki3 found an interesting edge case related to async iterators.

In Firefox and Node.js (where async iteration on ReadableStream is already supported), when you run this snippet:

const readable = new ReadableStream({
  start(c) {
    c.enqueue("a");
    c.enqueue("b");
  },
  cancel() {
    console.warn("cancelled");
  }
});

const it = readable.values();
const p1 = it.next().then(x => console.log("next 1 resolved with", x));
const p2 = it.return().then(x => console.log("return resolved with", x));
const p3 = it.next().then(x => console.log("next 2 resolved with", x));

you get:

next 1 resolved with { value: 'a', done: false }
cancelled
next 2 resolved with { done: true, value: undefined }
return resolved with { done: true, value: undefined }

This is quite surprising: the second next() promise resolves before the return() promise, even though it was called after return(). Intuitively, we would expect all async iterator calls to get queued. Indeed, if you do the same thing with an async generator:

async function* test() {
  try {
    yield "a";
    yield "b";
  } finally {
    console.warn("cancelled");
  }
}

const it = test();
const p1 = it.next().then(x => console.log("next 1 resolved with", x));
const p2 = it.return().then(x => console.log("return resolved with", x));
const p3 = it.next().then(x => console.log("next 2 resolved with", x));

then the promises resolve in the order of the original calls:

next 1 resolved with { value: 'a', done: false }
cancelled
return resolved with { value: undefined, done: true }
next 2 resolved with { value: undefined, done: true }

Yuki and I believe this to be a bug in the Web IDL specification. More precisely, the return() method should update the ongoing promise, such that future calls to next() and return() are properly chained. This aligns more closely with the behavior of async generators.

Suggested commit message:

Update ongoing promise in async iterator return() method

This fixes an edge case where manually calling return(); next() could result in the next() promise resolving before the return() promise.


(See WHATWG Working Mode: Changes for more details.)


Preview | Diff

Copy link
Member

@domenic domenic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! I think this is a bugfix and I hope someone from WebKit and/or Mozilla can quickly step up to approve. I take it that it has Chromium support already.

Copy link
Member

@annevk annevk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense that they should be aligned. Please file implementation bugs.

@domenic domenic merged commit 400ce04 into whatwg:main Feb 13, 2024
2 checks passed
@MattiasBuelens MattiasBuelens deleted the async-iterator-return-update-ongoing branch February 13, 2024 09:12
domenic pushed a commit to whatwg/streams that referenced this pull request Apr 24, 2024
Notably, this includes tests for promise resolution order of async iterators in the reference implementation. This requires updating webidl2js.

See whatwg/webidl#1387, web-platform-tests/wpt#44456, and jsdom/webidl2js#269 for context.
bartlomieju pushed a commit to denoland/deno that referenced this pull request May 13, 2024
…hod (#23642)

See whatwg/webidl#1387 for context.

There are new WPT tests for this change in
web-platform-tests/wpt#44456. They pass on my
local machine, but I'm not sure if I should update the WPT submodule for
all of Deno as part of this PR?

Fixes #22389

---------

Co-authored-by: Asher Gomez <ashersaupingomez@gmail.
bartlomieju pushed a commit to denoland/deno that referenced this pull request May 16, 2024
…hod (#23642)

See whatwg/webidl#1387 for context.

There are new WPT tests for this change in
web-platform-tests/wpt#44456. They pass on my
local machine, but I'm not sure if I should update the WPT submodule for
all of Deno as part of this PR?

Fixes #22389

---------

Co-authored-by: Asher Gomez <ashersaupingomez@gmail.
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.

3 participants