-
Notifications
You must be signed in to change notification settings - Fork 34
Does this pass through return
/throw
synchronously?
#223
Comments
As currently specified, it works exactly like async generators: calls to It's an interesting point that the async helpers could be more eager. I'd have to think more about the implications of that. What would you expect to happen to the promise returned by the call to (Re: |
As a use case, imagine an async iterator I would hope that One issue here. Let's say that when you call |
This is as much a hazard as it can be a help. I talked about this on the original issue, basically having this behaviour would make certain operators more footgunny to write. I think a better model to think about Like what you want here is cancellation, as you're essentially notifying multiple calls that their results no longer matter. It is rather a large shame the cancellation proposal has floundered and host APIs like |
return
/throw
properly?return
/throw
synchronously?
I don't have too much of a language design opinion here, but having iterator helpers that can mostly reuse async generator machinery except for return/throw might be annoying for implementation complexity. If there's no definitive compelling use case agreed upon by committee, and the reasoning to support synchronous For V8 it might not be too bad, but probably annoying. For self-hosting implementations, I wonder if having synchronous |
It seems pretty weird to solve this problem for iterator-helper-derived async iterators, and not other generator-derived async iterators? Like, will we expect people to stop using raw generators, and instead always write a wrapper like function betterAsyncGenerator(...args) {
return originalAsyncGenerator(...args).map(x => x);
} so that they can get this early-abort functionality? It feels like a better level at which to solve this would be to add some method to all generator-derived async iterators, e.g. |
@domenic The proposed change here wouldn't mean that iterator-helper-derived async iterators had this functionality when other iterators did not. Rather, the proposed change would be to preserve this functionality when the underlying iterator already supported it. As currently spec'd, even if you have a manually-implemented async iterator which can handle a call to |
That said, I think we're currently leaning towards not making any changes to the current spec, for the sake of staying consistent with async generators. Even though that means a manually-implemented async iterator which is capable of eagerly handling calls to |
Got it, that makes sense. And so I guess my "add a method" idea doesn't work.
Right. I'm saying it means that iterator-helper-derived async iterators, but other generator-derived async iterators do not. So I guess it just makes writing your own generators inferior to cobbling one together out of combinators, which is... slightly bad? I still think addressing this more generally for all generator-derived async iterators would be better, but now that I see the problem more clearly I guess it's not very easy. The best I can come up with is something like |
Looks like we're all pretty much in agreement here. Let's only preserve the functionality of the underlying iterator that an async-generator-based helper implementation could preserve. Thanks for prompting this discussion @glasser. |
It's a bummer that these helpers won't solve this use case, but I guess the bummer is more about the overall experience of using async iteration than about the helpers specifically, so that makes sense. |
I think we should maybe revisit this as part of #262. |
One challenge I have found with using async iteration is that it is challenging to do basic functionality like
map
in a way that works properly withreturn
/throw
. For example, it would look like one could implementmap
like:but calling
.return
on the value returned frommap
doesn't actually callit.return
immediately if it's blocked on reading fromit
, which can have poor results. You can build amap
that does pass throughit.return
immediately but it's much harder than writing an async generator. Lots of discussion about that on this issue.So my question, having recently discovered this proposal, is: does this proposal help with this concern? If you
return
an async iterator returned by.map(fn)
for example, is that passed through to the original iterator immediately, or only if it's currently yielding? I can't figure out the answer myself from README.md or DETAILs.md, and I don't understand the specification well enough to answer it myself there.The text was updated successfully, but these errors were encountered: