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

events: add EventEmitter.on to async iterate over events #27994

Closed
wants to merge 17 commits into from

Conversation

mcollina
Copy link
Member

Fixes: #27847.

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines

lib/events.js Outdated
},

throw(err) {
// TODO should we validate that err exists?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I think we shouldn't since it is allowed to throw undefined. I really hope users don't actually do it.

doc/api/events.md Outdated Show resolved Hide resolved
doc/api/events.md Outdated Show resolved Hide resolved
doc/api/events.md Outdated Show resolved Hide resolved
doc/api/events.md Outdated Show resolved Hide resolved
@benjamingr
Copy link
Member

CC @davidmarkclements since you maintain the .on shim in case you want to make a shim for this on NPM. If you don't I don't mind making one.

@mcollina mcollina force-pushed the on-async-iterator branch 2 times, most recently from 6e69e8d to b6542f0 Compare May 31, 2019 15:13
@zero1five
Copy link
Contributor

zero1five commented Jun 1, 2019

I like this!! 😆
I studied the this API for five or six hours, and there's something odd about it that I want to point out (if I stray from the subject, feel free to hide).

One test case seems to have a bug. I'm not sure what caused it Gist code

Specific steps for recurrence:

git pr 27994 upstream
./configure && make -j4
../Release/node ../index.js

It is clear that the async function exits directly after the for await of.

@davidmarkclements
Copy link
Member

CC @davidmarkclements since you maintain the .on shim in case you want to make a shim for this on NPM. If you don't I don't mind making one.

thanks @benjamingr - I've had the events.on shim ready since releasing events.once 😆 - I'm just waiting for core to land in case I need to adapt

Copy link
Contributor

@vsemozhetbyt vsemozhetbyt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@@ -694,6 +694,37 @@ async function run() {
run();
```

## events.on(emitter, event)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: needs to be placed before events.once() alphabetically?

doc/api/events.md Show resolved Hide resolved
@benjamingr
Copy link
Member

@zero1five thanks for the test case, definitely relevant I'll look into it when I'm in front of a computer

@benjamingr
Copy link
Member

@zero1five hey, I ran your code example but I wasn't able to figure out what the confusing part was. Do you mean how that pending promises do not keep the event loop live if there is no scheduled I/O?

@addaleax addaleax added the events Issues and PRs related to the events subsystem / EventEmitter. label Jun 2, 2019
@Raynos
Copy link
Contributor

Raynos commented Jun 7, 2019

Some events in node core emit a single value.

Would it be possible to add an option to this api to return the first value emitted instead of an array of all values emitted.

@benjamingr
Copy link
Member

@Raynos hey, long time no see. Happy to see you around here :]

Node already shipped (recently) an EventEmitter.once static method that does just that. https://nodejs.org/api/events.html#events_events_once_emitter_name

@Raynos
Copy link
Contributor

Raynos commented Jun 7, 2019

@Raynos hey, long time no see. Happy to see you around here :]

I was at the openjs summit in berlin, next time I see you i'll say hello properly.

Node already shipped (recently) an EventEmitter.once static method that does just that.

I meant an option to return the first value emitted, aka emitter.emit('foo', firstValue) instead of only listening to a single emission of the event like once.

The current implementation would require some destructuring in the common case

for await (const [message] of on(worker, 'message')) {
   ...
}

@benjamingr
Copy link
Member

@Raynos lol, I had no idea we were in the same room for two days :) definitely say hi next time!

@nodejs-github-bot
Copy link
Collaborator

doc/api/events.md Outdated Show resolved Hide resolved
doc/api/events.md Outdated Show resolved Hide resolved
mcollina and others added 2 commits December 23, 2019 00:18
Co-Authored-By: Benjamin Gruenbaum <inglor@gmail.com>
Co-Authored-By: Benjamin Gruenbaum <inglor@gmail.com>
@nodejs-github-bot
Copy link
Collaborator

@Trott
Copy link
Member

Trott commented Dec 23, 2019

CI passed. I think this is ready to land?

mcollina added a commit that referenced this pull request Dec 23, 2019
Fixes: #27847
PR-URL: #27994
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Rich Trott <rtrott@gmail.com>
@mcollina
Copy link
Member Author

Landed in 38a593b

@mcollina mcollina closed this Dec 23, 2019
@mcollina mcollina deleted the on-async-iterator branch December 23, 2019 08:29
BridgeAR pushed a commit that referenced this pull request Jan 3, 2020
Fixes: #27847
PR-URL: #27994
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Rich Trott <rtrott@gmail.com>
@BridgeAR BridgeAR mentioned this pull request Jan 7, 2020
BridgeAR added a commit that referenced this pull request Jan 7, 2020
Notable changes:

* assert:
  * Implement `assert.match()` and `assert.doesNotMatch()` (Ruben
    Bridgewater) #30929
* events:
  * Add `EventEmitter.on` to async iterate over events (Matteo Collina)
    #27994
  * Allow monitoring error events (Gerhard Stoebich)
    #30932
* fs:
  * Allow overriding `fs` for streams (Robert Nagy)
    #29083
* perf_hooks:
  * Move `perf_hooks` out of experimental (legendecas)
    #31101
* repl:
  * Implement ZSH-like reverse-i-search (Ruben Bridgewater)
    #31006
* tls:
  * Add PSK (pre-shared key) support (Denys Otrishko)
    #23188

PR-URL: #31238
BridgeAR added a commit that referenced this pull request Jan 7, 2020
Notable changes:

* assert:
  * Implement `assert.match()` and `assert.doesNotMatch()` (Ruben
    Bridgewater) #30929
* events:
  * Add `EventEmitter.on` to async iterate over events (Matteo Collina)
    #27994
  * Allow monitoring error events (Gerhard Stoebich)
    #30932
* fs:
  * Allow overriding `fs` for streams (Robert Nagy)
    #29083
* perf_hooks:
  * Move `perf_hooks` out of experimental (legendecas)
    #31101
* repl:
  * Implement ZSH-like reverse-i-search (Ruben Bridgewater)
    #31006
* tls:
  * Add PSK (pre-shared key) support (Denys Otrishko)
    #23188

PR-URL: #31238
BridgeAR added a commit that referenced this pull request Jan 7, 2020
Notable changes:

* assert:
  * Implement `assert.match()` and `assert.doesNotMatch()` (Ruben
    Bridgewater) #30929
* events:
  * Add `EventEmitter.on` to async iterate over events (Matteo Collina)
    #27994
  * Allow monitoring error events (Gerhard Stoebich)
    #30932
* fs:
  * Allow overriding `fs` for streams (Robert Nagy)
    #29083
* perf_hooks:
  * Move `perf_hooks` out of experimental (legendecas)
    #31101
* repl:
  * Implement ZSH-like reverse-i-search (Ruben Bridgewater)
    #31006
* tls:
  * Add PSK (pre-shared key) support (Denys Otrishko)
    #23188

PR-URL: #31238
targos pushed a commit that referenced this pull request Jan 14, 2020
Fixes: #27847
PR-URL: #27994
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Rich Trott <rtrott@gmail.com>
}

// If the iterator is finished, resolve to done
if (finished) {
Copy link

@jayflo jayflo Jan 30, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stupid question: how does finished get set to true in the non-error case? From what I see here, after the final event is resolved, won't the for await of loop will be waiting on a promise from unconsumedPromises? It seems like some sort of "on finished" callback would be needed.

BethGriggs pushed a commit that referenced this pull request Feb 6, 2020
Fixes: #27847
PR-URL: #27994
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Rich Trott <rtrott@gmail.com>
@MylesBorins MylesBorins mentioned this pull request Feb 8, 2020
targos pushed a commit that referenced this pull request Feb 11, 2020
Notable changes:

New assert APIs

The `assert` module now provides experimental `assert.match()` and
`assert.doesNotMatch()` methods. They will validate that the first argument is a
string and matches (or does not match) the provided regular expression

This is an experimental feature.

Ruben Bridgewater [#30929](#30929).

Advanced serialization for IPC

The `child_process` and `cluster` modules now support a `serialization` option
to change the serialization mechanism used for IPC. The option can have one of
two values:

* `'json'` (default): `JSON.stringify()` and `JSON.parse()` are used. This is
  how message serialization was done before.
* `'advanced'`: The serialization API of the `v8` module is used. It is based on
  the HTML structured clone algorithm.
  and is able to serialize more built-in JavaScript object types, such as
  `BigInt`, `Map`, `Set` etc. as well as circular data structures.

Anna Henningsen [#30162](#30162).

CLI flags

The new `--trace-exit` CLI flag makes Node.js print a stack trace whenever the
Node.js environment is exited proactively (i.e. by invoking the `process.exit()`
function or pressing Ctrl+C).

legendecas [#30516](#30516).

___

The new `--trace-uncaught` CLI flag makes Node.js print a stack trace at the
time of throwing uncaught exceptions, rather than at the creation of the `Error`
object, if there is any.
This option is not enabled by default because it may affect garbage collection
behavior negatively.

Anna Henningsen [#30025](#30025).

___

The `--disallow-code-generation-from-strings` V8 CLI flag is now whitelisted in
the `NODE_OPTIONS` environment variable.

Shelley Vohr [#30094](#30094).

New crypto APIs

For DSA and ECDSA, a new signature encoding is now supported in addition to the
existing one (DER). The `verify` and `sign` methods accept a `dsaEncoding`
option, which can have one of two values:

* `'der'` (default): DER-encoded ASN.1 signature structure encoding `(r, s)`.
* `'ieee-p1363'`: Signature format `r || s` as proposed in IEEE-P1363.

Tobias Nießen [#29292](#29292).

___

A new method was added to `Hash`: `Hash.prototype.copy`. It makes it possible to
clone the internal state of a `Hash` object into a new `Hash` object, allowing
to compute the digest between updates.

Ben Noordhuis [#29910](#29910).

Dependency updates

libuv was updated to 1.34.0. This includes fixes to `uv_fs_copyfile()` and
`uv_interface_addresses()` and adds two new functions: `uv_sleep()` and
`uv_fs_mkstemp()`.

Colin Ihrig [#30783](#30783).

___

V8 was updated to 7.8.279.23. This includes performance improvements to object
destructuring, RegExp match failures and WebAssembly startup time.
The official release notes are available at https://v8.dev/blog/v8-release-78.

Michaël Zasso [#30109](#30109).

New EventEmitter APIs

The new `EventEmitter.on` static method allows to async iterate over events.

Matteo Collina [#27994](#27994).

___

It is now possible to monitor `'error'` events on an `EventEmitter` without
consuming the emitted error by installing a listener using the symbol
`EventEmitter.errorMonitor`.

Gerhard Stoebich [#30932](#30932).

___

Using `async` functions with event handlers is problematic, because it
can lead to an unhandled rejection in case of a thrown exception.

The experimental `captureRejections` option in the `EventEmitter` constructor or
the global setting change this behavior, installing a
`.then(undefined, handler)` handler on the `Promise`. This handler routes the
exception asynchronously to the `Symbol.for('nodejs.rejection')` method if there
is one, or to the `'error'` event handler if there is none.

Setting `EventEmitter.captureRejections = true` will change the default for all
new instances of `EventEmitter`.

This is an experimental feature.

Matteo Collina [#27867](#27867).

Performance Hooks are no longer experimental

The `perf_hooks` module is now considered a stable API.

legendecas [#31101](#31101).

Introduction of experimental WebAssembly System Interface (WASI) support

A new core module, `wasi`, is introduced to provide an implementation of the
[WebAssembly System Interface](https://wasi.dev/) specification.
WASI gives sandboxed WebAssembly applications access to the
underlying operating system via a collection of POSIX-like functions.

This is an experimental feature.

Colin Ihrig [#30258](#30258).

PR-URL: #31691
targos pushed a commit that referenced this pull request Feb 11, 2020
Notable changes:

New assert APIs

The `assert` module now provides experimental `assert.match()` and
`assert.doesNotMatch()` methods. They will validate that the first argument is a
string and matches (or does not match) the provided regular expression

This is an experimental feature.

Ruben Bridgewater [#30929](#30929).

Advanced serialization for IPC

The `child_process` and `cluster` modules now support a `serialization` option
to change the serialization mechanism used for IPC. The option can have one of
two values:

* `'json'` (default): `JSON.stringify()` and `JSON.parse()` are used. This is
  how message serialization was done before.
* `'advanced'`: The serialization API of the `v8` module is used. It is based on
  the HTML structured clone algorithm.
  and is able to serialize more built-in JavaScript object types, such as
  `BigInt`, `Map`, `Set` etc. as well as circular data structures.

Anna Henningsen [#30162](#30162).

CLI flags

The new `--trace-exit` CLI flag makes Node.js print a stack trace whenever the
Node.js environment is exited proactively (i.e. by invoking the `process.exit()`
function or pressing Ctrl+C).

legendecas [#30516](#30516).

___

The new `--trace-uncaught` CLI flag makes Node.js print a stack trace at the
time of throwing uncaught exceptions, rather than at the creation of the `Error`
object, if there is any.
This option is not enabled by default because it may affect garbage collection
behavior negatively.

Anna Henningsen [#30025](#30025).

___

The `--disallow-code-generation-from-strings` V8 CLI flag is now whitelisted in
the `NODE_OPTIONS` environment variable.

Shelley Vohr [#30094](#30094).

New crypto APIs

For DSA and ECDSA, a new signature encoding is now supported in addition to the
existing one (DER). The `verify` and `sign` methods accept a `dsaEncoding`
option, which can have one of two values:

* `'der'` (default): DER-encoded ASN.1 signature structure encoding `(r, s)`.
* `'ieee-p1363'`: Signature format `r || s` as proposed in IEEE-P1363.

Tobias Nießen [#29292](#29292).

___

A new method was added to `Hash`: `Hash.prototype.copy`. It makes it possible to
clone the internal state of a `Hash` object into a new `Hash` object, allowing
to compute the digest between updates.

Ben Noordhuis [#29910](#29910).

Dependency updates

libuv was updated to 1.34.0. This includes fixes to `uv_fs_copyfile()` and
`uv_interface_addresses()` and adds two new functions: `uv_sleep()` and
`uv_fs_mkstemp()`.

Colin Ihrig [#30783](#30783).

___

V8 was updated to 7.8.279.23. This includes performance improvements to object
destructuring, RegExp match failures and WebAssembly startup time.
The official release notes are available at https://v8.dev/blog/v8-release-78.

Michaël Zasso [#30109](#30109).

New EventEmitter APIs

The new `EventEmitter.on` static method allows to async iterate over events.

Matteo Collina [#27994](#27994).

___

It is now possible to monitor `'error'` events on an `EventEmitter` without
consuming the emitted error by installing a listener using the symbol
`EventEmitter.errorMonitor`.

Gerhard Stoebich [#30932](#30932).

___

Using `async` functions with event handlers is problematic, because it
can lead to an unhandled rejection in case of a thrown exception.

The experimental `captureRejections` option in the `EventEmitter` constructor or
the global setting change this behavior, installing a
`.then(undefined, handler)` handler on the `Promise`. This handler routes the
exception asynchronously to the `Symbol.for('nodejs.rejection')` method if there
is one, or to the `'error'` event handler if there is none.

Setting `EventEmitter.captureRejections = true` will change the default for all
new instances of `EventEmitter`.

This is an experimental feature.

Matteo Collina [#27867](#27867).

Performance Hooks are no longer experimental

The `perf_hooks` module is now considered a stable API.

legendecas [#31101](#31101).

Introduction of experimental WebAssembly System Interface (WASI) support

A new core module, `wasi`, is introduced to provide an implementation of the
[WebAssembly System Interface](https://wasi.dev/) specification.
WASI gives sandboxed WebAssembly applications access to the
underlying operating system via a collection of POSIX-like functions.

This is an experimental feature.

Colin Ihrig [#30258](#30258).

PR-URL: #31691
goto-bus-stop added a commit to browserify/events that referenced this pull request Feb 28, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
events Issues and PRs related to the events subsystem / EventEmitter. semver-minor PRs that contain new features and should be released in the next minor version.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Async Iterable EventEmitter.on(emitter, "event")