Open conartist6 opened 3 years ago
I guess the question is: what's the point? Is it timing, so that other operations are sequenced after underlying resources are released? Is it error handling? Will subscribe code know how to handle cleanup failure in a meaningful way?
For fun I implemented an async iterator of fromEvent
:
I think fromEvent
is better abstracted as an observable, rather then an async iterator, even though it might be better consumed inside a for await ... of
. You’ll notice there are a few footguns in this implementation, including a potential infinite loop if we forget to change the isListening
flag (if a child iterator closes when the event buffer is empty).
You will also notice that there is a subtle difference in behavior if more then one event is dispatched in the same tick. An observable will run in the same tick but an async iterator will always wait until the next tick to run the handler. This subtle difference might be important in some user code where an event triggered would alter the behavior of how subsequent events are fired.
Thirdly, notice that I have to create my own process loop that runs once per tick. I’m not an engine expert so this might be minor, but I do wonder about the performance implication of this, especially if the task required to run in this main loop is non-trivial, or if an inexperienced (or tired) programmer fails to find an optimized version to check if an action is needed.
@runarberg I don't think we're talking about the same thing. You're talking about making Observables into async iterables. I'm talking about making async iterables into observables. In general I agree that async iteration is not well suited to the general pubsub use case, particularly when there are multiple subscribers. For one thing there's the problem you mention with sync things becoming async, which leads to lost performance (and the potential for flickering behavior in UIs). Another problem is that stack traces are lost, and it becomes hard to tell why things happened. Also the order in which subscribers are notified about an event is then determined by some very hidden engine internals and may (or may not be) essentially random.
Since async iterables have these problems, if they are the data source it may make sense to convert them to observables when there are multiple subscribers interested in the "events" (resolution of iterator step promises) they produce. My wish is that this be possible, and that an observable created from a generic async iterator be able to ensure that the async underlying iterator is cleaned up correctly.
I find it is not a well known feature but the spec allows sync and async iterators to specify a
return()
method. This in turn enables the creation of iterables that have handles to underlying resources, like files or connections. Since resources referred to by handles are usually accessed (in modern styles) with async APIs, I'm particularly interested in theAsyncIterator.return
method, which returns a promise. If such a method exists, there is no way to know that it would be safe not to call it, and it would seem to me unwise not to await on the promise. Doing so would cause errors to escape their context, instead bubbling up to the global promise rejection handler. Thus, in order to be able to create Observables from async iterators which hold underlying resources, unsubscribe should be able to return a promise.