-
Notifications
You must be signed in to change notification settings - Fork 29.6k
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
Async Iterable EventEmitter.on(emitter, "event")
#27847
Comments
Addressing @jasnell 's points from that PR:
This is true with a
True, and this is by design for the most part. Async iterator libraries like axax have utilities like |
My main concern about this API is that EE does not support backpressure. Essentially the following: const foos = on(emitter, 'foo');
for await (const foo of foos) {
await doSomethingRemotely()
} Will have all events queue up and processed one at a time. Are we ok with it? I'm struggling to make up my mind. I think some safety measure should be built in (maybe with an option), like the following: const foos = on(emitter, 'foo', { maxQueue: 1000 });
// will throw if the number of accumulated events waiting to be processed are
// over 1000.
for await (const foo of foos) {
await doSomethingRemotely()
} What do you think? On another note, we need to make sure the following (or similar) works: const foos = on(emitter, 'foo');
emitter.on('end', foos.removeListener.bind(foos)); // or similar
for await (const foo of foos) {
await doSomethingRemotely()
}
// the loop will terminate when 'end' is emitted |
I think we are - events that are push can't do backpressure - that's why we have readable streams. We can and should be explicit about this in the documentation. I don't think we have to provide maxQueue because I definitely see use cases where we'd be fine with a queue of a few thousand items. Not feeling strongly about this though and ready to be convinced.
Oh interesting, can a listener detect it being removed? Are we sure we actually have to support this? |
we can make it work by having removeListener clear the queue and putting a |
Would it be an issue if the emitter was been |
Yes, but that would happen even with a normal event handler. I don't think it's going to be a problem at all. |
A problem that I handled with const foos = on(emitter, 'foo');
process.nextTick(() => {
emitter.emit('foo', 'a', 'b')
})
for await (const [first, second] of foos) {
} |
As a more friendly syntax, we could support this case... const foos = on(emitter, 'foo');
emitter.on('end', foos.removeListener.bind(foos)); // or similar
for await (const foo of foos) {
await doSomethingRemotely()
} ... By declaring terminal events when the async iterator is created... const foos = on(emitter, 'foo', { until: 'end' });
for await (const foo of foos) {
await doSomethingRemotely()
} |
We also need to consider what happens in the case... const foos = on(emitter, 'foo');
emitter.removeAllListeners('foo')
for await (const foo of foos) {} The async iterator needs to be able to clean itself up if the listener it registered has been removed. |
We can use the |
In case it's of interest, something very similar is already possible with IxJS: Once the emitter is wrapped with Ix, it can be used with |
Matteo already has an implementation :D |
This idea seems good in isolation, but would it be worth seeing whether Emitter would be a good return value for |
Fixes: #27847 PR-URL: #27994 Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Gus Caplan <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Rich Trott <[email protected]>
Fixes: #27847 PR-URL: #27994 Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Gus Caplan <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Rich Trott <[email protected]>
Fixes: #27847 PR-URL: #27994 Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Gus Caplan <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Rich Trott <[email protected]>
Continuing the discussion from the
once
PR. Regarding the discussion ofEventEmitter.on(emitter, "eventName")
events.on(emitter, name)
EventEmitter
>string
>AsyncIterable
>Creates an
AsyncIterable
that yields promises for the values of the given eventname
in the given EventEmitter. The iterable rejects the next promise when the EventEmitter emits 'error'. Calling.return
on the iterable removes the subscription which means the iterable unsubscribes automatically when afor await
loop is broken or returned from.Here is an example of the API:
Or with
for await
syntax:cc @mcollina @jasnell @MylesBorins @addaleax @BridgeAR
The text was updated successfully, but these errors were encountered: