- From: Ben Lesh <notifications@github.com>
- Date: Wed, 05 Jan 2022 12:11:39 -0800
- To: whatwg/dom <dom@noreply.github.com>
- Cc: Subscribed <subscribed@noreply.github.com>
- Message-ID: <whatwg/dom/issues/1038/1006042750@github.com>
In general, I like this sort of idea. However, I'd caution against it because of the nuance involved with converting something that's entirely push-based (EventTarget) to something that is pull-push based (AsyncIterable). The latter is much more complicated and that complication/nuance is generally lost in async functions with for-await loops.
We looked at making RxJS's observable implement `[Symbol.asyncIterator]` but ultimately found it might be more problematic for users than beneficial. It comes down to the fact there are really 4 basic ways (and oodles of others) people will want to deal with observables in a for-await loop, and the fact that the most intuitive one of those ways has a lot of overhead (mental and technical) that people will have a hard time understanding. Ultimately, the team decided not to go ahead with the idea, and instead I [published a library to convert observables to AsyncIterables](https://www.npmjs.com/package/rxjs-for-await).
Consider the complexity added even in this simple case:
```ts
textInput.addEventListener('input', async (e) => {
// this is hit IMMEDIATELY every time the input is changed
const data = await getData(textInput.value);
render(data);
});
// vs
for await (const e of textInput.on('input')) {
// This is hit IMMEDIATELY the FIRST time the input is changed
// however, if the input is changed while `getData` is doing its thing,
// then it will not be hit again until `getData` finishes doing its thing.
// BUT, if the button is clicked two or three times while `getData` is doing
// its thing, THEN you have to wait for each of the previous events to be
// processed.
// ADDITIONALLY, the state of `textInput.value`, and the rest of the app,
// will have changed by the time this is hit in those cases, so you may
// end up sending something you're not expecting.
const data = await getData(textInput.value);
render(data);
}
```
In short, while I think this improves the superficial ergonomics of `EventTarget`, ultimately I think it makes the code and the type itself harder to reason about because the underlying type and its interactions are more complex.
A pushed based type, like an observable, in likely a better choice for this use-case IMO: https://github.com/whatwg/dom/issues/544
However, I do think that there's some merit to making other things, like `ReadableStream` and the like, into AsyncIterables, as the complexity matches pretty much 1:1.
--
Reply to this email directly or view it on GitHub:
https://github.com/whatwg/dom/issues/1038#issuecomment-1006042750
You are receiving this because you are subscribed to this thread.
Message ID: <whatwg/dom/issues/1038/1006042750@github.com>
Received on Wednesday, 5 January 2022 20:11:52 UTC