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

Info about rejected promises in the async iterator protocol #27636

Closed
mrft opened this issue Jun 28, 2023 · 2 comments · Fixed by #34069
Closed

Info about rejected promises in the async iterator protocol #27636

mrft opened this issue Jun 28, 2023 · 2 comments · Fixed by #34069
Labels
Content:JS JavaScript docs

Comments

@mrft
Copy link

mrft commented Jun 28, 2023

MDN URL

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols

What specific section or headline is this issue about?

The async iterator and async iterable protocols

What information was incorrect, unhelpful, or incomplete?

I was searching for information about the behavior of Async Iterators when the promise would reject.

But I found no info at all.

What did you expect to see?

Information about what it means when the promise returned from the next() call rejects.

For example: if I were to write an iterator that was getting some API results page-per-page, one of the http requests could fail. In that case, the promise could reject.
Then the question for me is: if the promise rejects, is the caller allowed to retry by calling next() again?
And is the iterator then expected to retry the same thing, in this case: retry the http request to the same url?

It could also be that this protocol explicitly means that the promise MUST resolve, otherwise it is not implementing the protocol, but in that case it is up to every async iterator to specify what it will return when an error occurs, and that would be a pity since we already have the rejected promise mechanism for that.

And what happens currently if an async generator function yields a rejected promise? Will it keep or rollback its 'state' (allowing you to repeat the next call), or will it completely fail? What will the result of the following next() call be in this case?

Do you have any supporting links, references, or citations?

Maybe this discussion is somewhat related: tc39/proposal-async-iterator-helpers#5

Do you have anything more you want to share?

I started thinking about this because I am writing a library called itr8 library. This library produces what I call "transIterators", which are basically unary functions that transform iterators, as they will take an (sync or async) iterator as input, and return another iterator as output.

I started thinking about a retry() operator, to easily abstract a retry mechansim, which can the be applied to any problem where you'd need a retry strategy.
Of course this begged the question: "when should we retry something?" A rejected promise immediately came to mind, so I checked what I could find in the docs about what the async iterator protocol said about rejected promise, which was - to my surprise - nothing at all.

MDN metadata

Page report details
@mrft mrft added the needs triage Triage needed by staff and/or partners. Automatically applied when an issue is opened. label Jun 28, 2023
@github-actions github-actions bot added the Content:JS JavaScript docs label Jun 28, 2023
@Josh-Cena Josh-Cena removed the needs triage Triage needed by staff and/or partners. Automatically applied when an issue is opened. label Jun 29, 2023
@Josh-Cena
Copy link
Member

Iterator error handling has always something I'm dreading to document. See for examples: tc39/ecma262#2819. But it's necessary eventually.

@bakkot
Copy link
Contributor

bakkot commented Sep 19, 2023

The most useful thing to look at is for await. The behavior of for await is, if next returns a rejected promise, the loop will immediately stop, and will not call .return on the iterator (as it would if the loop early-exited any other way). In other words, for await treats next returning a rejected promise as indicating that the iterator is done.

Also, when using an async generator, the only way for next to give a rejected promise is if the body of the generator throws an uncaught exception, in which case the generator is finished and any subsequent call to .next will resolve with { done: true }.

Now, of course, you can implement a different behavior if you want to. But if you want to match the behavior of the things in the language, "if the promise returned by .next() rejects then the iterator is finished" is the principle to follow, and I think that would be a reasonable thing to write down without getting into all of the edge cases around async-from-sync and so on.

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

Successfully merging a pull request may close this issue.

3 participants