Browse Source

doc: improvements to events.markdown copy

General improvements to events.markdown copy including a
bit of restructuring and improved examples

PR-URL: https://github.com/nodejs/node/pull/4468
Reviewed-By: Myles Borins <myles.borins@gmail.com>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
process-exit-stdio-flushing
James M Snell 9 years ago
parent
commit
a0130e16e5
  1. 352
      doc/api/events.markdown

352
doc/api/events.markdown

@ -4,88 +4,257 @@
<!--type=module-->
Many objects in Node.js emit events: a [`net.Server`][] emits an event each
time a peer connects to it, a [`fs.ReadStream`][] emits an event when the file
is opened. All objects which emit events are instances of `events.EventEmitter`.
You can access this module by doing: `require("events");`
Much of the Node.js core API is built around an idiomatic asynchronous
event-driven architecture in which certain kinds of objects (called "emitters")
periodically emit named events that cause Function objects ("listeners") to be
called.
Typically, event names are represented by a camel-cased string, however,
there aren't any strict restrictions on that, as any valid property key will be
accepted.
For instance: a [`net.Server`][] object emits an event each time a peer
connects to it; a [`fs.ReadStream`][] emits an event when the file is opened;
a [stream][] emits an event whenever data is available to be read.
Functions can then be attached to objects, to be executed when an event
is emitted. These functions are called _listeners_. Inside a listener
function, `this` refers to the `EventEmitter` that the listener was
attached to.
All objects that emit events are instances of the `EventEmitter` class. These
objects expose an `eventEmitter.on()` function that allows one or more
Functions to be attached to named events emitted by the object. Typically,
event names are camel-cased strings but any valid JavaScript property key
can be used.
When the `EventEmitter` object emits an event, all of the Functions attached
to that specific event are called _synchronously_. Any values returned by the
called listeners are _ignored_ and will be discarded.
## Class: events.EventEmitter
The following example shows a simple `EventEmitter` instance with a single
listener. The `eventEmitter.on()` method is used to register listeners, while
the `eventEmitter.emit()` method is used to trigger the event.
Use `require('events')` to access the EventEmitter class.
const EventEmitter = require('events');
const util = require('util');
```javascript
const EventEmitter = require('events');
```
function MyEmitter() {
EventEmitter.call(this);
}
util.inherits(MyEmitter, EventEmitter);
When an `EventEmitter` instance experiences an error, the typical action is
to emit an `'error'` event. Error events are treated as a special case in
Node.js. If there is no listener for it, then the default action is to print
a stack trace and exit the program.
const myEmitter = new MyEmitter();
myEmitter.on('event', function() {
console.log('an event occurred!');
});
myEmitter.emit('event');
All EventEmitters emit the event `'newListener'` when new listeners are
added and `'removeListener'` when a listener is removed.
Any object can become an `EventEmitter` through inheritance. The example above
uses the traditional Node.js style prototypical inheritance using
the `util.inherits()` method. It is, however, possible to use ES6 classes as
well:
### Inheriting from 'EventEmitter'
const EventEmitter = require('events');
Inheriting from `EventEmitter` is no different from inheriting from any other
constructor function. For example:
class MyEmitter extends EventEmitter {}
'use strict';
const util = require('util');
const EventEmitter = require('events');
const myEmitter = new MyEmitter();
myEmitter.on('event', function() {
console.log('an event occurred!');
});
myEmitter.emit('event');
## Passing arguments and `this` to listeners
The `eventEmitter.emit()` method allows an arbitrary set of arguments to be
passed to the listener functions. It is important to keep in mind that when an
ordinary listener function is called by the `EventEmitter`, the standard `this`
keyword is intentionally set to reference the `EventEmitter` to which the
listener is attached.
const myEmitter = new MyEmitter();
myEmitter.on('event', function(a, b) {
console.log(a, b, this);
// Prints:
// a b MyEmitter {
// domain: null,
// _events: { event: [Function] },
// _eventsCount: 1,
// _maxListeners: undefined }
});
myEmitter.emit('event', 'a', 'b');
function MyEventEmitter() {
// Initialize necessary properties from `EventEmitter` in this instance
EventEmitter.call(this);
}
It is possible to use ES6 Arrow Functions as listeners, however, when doing so,
the `this` keyword will no longer reference the `EventEmitter` instance:
const myEmitter = new MyEmitter();
myEmitter.on('event', (a, b) => {
console.log(a, b, this);
// Prints: a b {}
});
myEmitter.emit('event', 'a', 'b');
## Asynchronous vs. Synchronous
The `EventListener` calls all listeners synchronously in the order in which
they were registered. This is important to ensure the proper sequencing of
events and to avoid race conditions or logic errors. When appropriate,
listener functions can switch to an asynchronous mode of operation using
the `setImmediate()` or `process.nextTick()` methods:
const myEmitter = new MyEmitter();
myEmitter.on('event', (a, b) => {
setImmediate(() => {
console.log('this happens asynchronously');
});
});
myEmitter.emit('event', 'a', 'b');
## Handling events only once
When a listener is registered using the `eventEmitter.on()` method, that
listener will be invoked _every time_ the named event is emitted.
const myEmitter = new MyEmitter();
var m = 0;
myEmitter.on('event', () => {
console.log(++m);
});
myEmitter.emit('event');
// Prints: 1
myEmitter.emit('event');
// Prints: 2
Using the `eventEmitter.once()` method, it is possible to register a listener
that is immediately unregistered after it is called.
const myEmitter = new MyEmitter();
var m = 0;
myEmitter.once('event', () => {
console.log(++m);
});
myEmitter.emit('event');
// Prints: 1
myEmitter.emit('event');
// Ignored
## Error events
When an error occurs within an `EventEmitter` instance, the typical action is
for an `'error'` event to be emitted. These are treated as a special case
within Node.js.
If an `EventEmitter` does _not_ have at least one listener registered for the
`'error'` event, and an `'error'` event is emitted, the error is thrown, a
stack trace is printed, and the Node.js process exits.
const myEmitter = new MyEmitter();
myEmitter.emit('error', new Error('whoops!'));
// Throws and crashes Node.js
To guard against crashing the Node.js process, developers can either register
a listener for the `process.on('uncaughtException')` event or use the
[`domain`][] module (_Note, however, that the `domain` module has been
deprecated_).
const myEmitter = new MyEmitter();
process.on('uncaughtException', (err) => {
console.log('whoops! there was an error');
});
myEmitter.emit('error', new Error('whoops!'));
// Prints: whoops! there was an error
// Inherit functions from `EventEmitter`'s prototype
util.inherits(MyEventEmitter, EventEmitter);
As a best practice, developers should always register listeners for the
`'error'` event:
### Class Method: EventEmitter.listenerCount(emitter, event)
const myEmitter = new MyEmitter();
myEmitter.on('error', (err) => {
console.log('whoops! there was an error');
});
myEmitter.emit('error', new Error('whoops!'));
// Prints: whoops! there was an error
## Class: EventEmitter
Stability: 0 - Deprecated: Use [emitter.listenerCount][] instead.
The `EventEmitter` class is defined and exposed by the `events` module:
Returns the number of listeners for a given event.
const EventEmitter = require('events');
All EventEmitters emit the event `'newListener'` when new listeners are
added and `'removeListener'` when a listener is removed.
### Event: 'newListener'
* `event` {String|Symbol} The event name
* `listener` {Function} The event handler function
This event is emitted *before* a listener is added. When this event is
triggered, the listener has not been added to the array of listeners for the
`event`. Any listeners added to the event `name` in the newListener event
callback will be added *before* the listener that is in the process of being
added.
The `EventEmitter` instance will emit it's own `'newListener'` event *before*
a listener is added to it's internal array of listeners.
Listeners registered for the `'newListener'` event will be passed the event
name and a reference to the listener being added.
The fact that the event is triggered before adding the listener has a subtle
but important side effect: any *additional* listeners registered to the same
`name` *within* the `'newListener'` callback will be inserted *before* the
listener that is in the process of being added.
const myEmitter = new MyEmitter();
// Only do this once so we don't loop forever
myEmitter.once('newListener', (event, listener) => {
if (event === 'event') {
// Insert a new listener in front
myEmitter.on('event', () => {
console.log('B');
});
}
});
myEmitter.on('event', () => {
console.log('A');
});
myEmitter.emit('event');
// Prints:
// B
// A
### Event: 'removeListener'
* `event` {String|Symbol} The event name
* `listener` {Function} The event handler function
This event is emitted *after* a listener is removed. When this event is
triggered, the listener has been removed from the array of listeners for the
`event`.
The `'removeListener'` event is emitted *after* a listener is removed.
### EventEmitter.listenerCount(emitter, event)
Stability: 0 - Deprecated: Use [`emitter.listenerCount()`][] instead.
A class method that returns the number of listeners for the given `event`
registered on the given `emitter`.
const myEmitter = new MyEmitter();
myEmitter.on('event', () => {});
myEmitter.on('event', () => {});
console.log(EventEmitter.listenerCount(myEmitter, 'event'));
// Prints: 2
### EventEmitter.defaultMaxListeners
[`emitter.setMaxListeners(n)`][] sets the maximum on a per-instance basis.
This class property lets you set it for *all* `EventEmitter` instances,
current and future, effective immediately. Use with care.
By default, a maximum of `10` listeners can be registered for any single
event. This limit can be changed for individual `EventEmitter` instances
using the [`emitter.setMaxListeners(n)`][] method. To change the default
for *all* `EventEmitter` instances, the `EventEmitter.defaultMaxListeners`
property can be used.
Note that [`emitter.setMaxListeners(n)`][] still has precedence over
`EventEmitter.defaultMaxListeners`.
Take caution when setting the `EventEmitter.defaultMaxListeners` because the
change effects *all* `EventEmitter` instances, including those created before
the change is made. However, calling [`emitter.setMaxListeners(n)`][] still has
precedence over `EventEmitter.defaultMaxListeners`.
Note that this is not a hard limit. The `EventEmitter` instance will allow
more listeners to be added but will output a trace warning to stderr indicating
that a `possible EventEmitter memory leak` has been detected. For any single
`EventEmitter`, the `emitter.getMaxListeners()` and `emitter.setMaxListeners()`
methods can be used to temporarily avoid this warning:
emitter.setMaxListeners(emitter.getMaxListeners() + 1);
emitter.once('event', () => {
// do stuff
emitter.setMaxListeners(Math.max(emitter.getMaxListeners() - 1, 0));
});
### emitter.addListener(event, listener)
@ -93,77 +262,72 @@ Alias for `emitter.on(event, listener)`.
### emitter.emit(event[, arg1][, arg2][, ...])
Calls each of the listeners in order with the supplied arguments.
Synchronously calls each of the listeners registered for `event`, in the order
they were registered, passing the supplied arguments to each.
Returns `true` if event had listeners, `false` otherwise.
### emitter.getMaxListeners()
Returns the current max listener value for the emitter which is either set by
[`emitter.setMaxListeners(n)`][] or defaults to
Returns the current max listener value for the `EventEmitter` which is either
set by [`emitter.setMaxListeners(n)`][] or defaults to
[`EventEmitter.defaultMaxListeners`][].
This can be useful to increment/decrement max listeners to avoid the warning
while not being irresponsible and setting a too big number.
### emitter.listenerCount(event)
emitter.setMaxListeners(emitter.getMaxListeners() + 1);
emitter.once('event', () => {
// do stuff
emitter.setMaxListeners(Math.max(emitter.getMaxListeners() - 1, 0));
});
### emitter.listenerCount(type)
* `event` {Value} The type of event
* `type` {Value} The type of event
Returns the number of listeners listening to the `type` of event.
Returns the number of listeners listening to the `event` type.
### emitter.listeners(event)
Returns a copy of the array of listeners for the specified event.
Returns a copy of the array of listeners for the specified `event`.
server.on('connection', (stream) => {
console.log('someone connected!');
});
console.log(util.inspect(server.listeners('connection'))); // [ [Function] ]
console.log(util.inspect(server.listeners('connection')));
// Prints: [ [Function] ]
### emitter.on(event, listener)
Adds a listener to the end of the listeners array for the specified `event`.
No checks are made to see if the `listener` has already been added. Multiple
calls passing the same combination of `event` and `listener` will result in the
`listener` being added multiple times.
Adds the `listener` function to the end of the listeners array for the
specified `event`. No checks are made to see if the `listener` has already
been added. Multiple calls passing the same combination of `event` and
`listener` will result in the `listener` being added, and called, multiple
times.
server.on('connection', (stream) => {
console.log('someone connected!');
});
Returns emitter, so calls can be chained.
Returns a reference to the `EventEmitter` so calls can be chained.
### emitter.once(event, listener)
Adds a **one time** listener for the event. This listener is
invoked only the next time the event is fired, after which
it is removed.
Adds a **one time** `listener` function for the `event`. This listener is
invoked only the next time `event` is triggered, after which it is removed.
server.once('connection', (stream) => {
console.log('Ah, we have our first user!');
});
Returns emitter, so calls can be chained.
Returns a reference to the `EventEmitter` so calls can be chained.
### emitter.removeAllListeners([event])
Removes all listeners, or those of the specified event. It's not a good idea to
remove listeners that were added elsewhere in the code, especially when it's on
an emitter that you didn't create (e.g. sockets or file streams).
Removes all listeners, or those of the specified `event`.
Note that it is bad practice to remove listeners added elsewhere in the code,
particularly when the `EventEmitter` instance was created by some other
component or module (e.g. sockets or file streams).
Returns emitter, so calls can be chained.
Returns a reference to the `EventEmitter` so calls can be chained.
### emitter.removeListener(event, listener)
Removes a listener from the listener array for the specified event.
**Caution**: changes array indices in the listener array behind the listener.
Removes the specified `listener` from the listener array for the specified
`event`.
var callback = function(stream) {
console.log('someone connected!');
@ -177,19 +341,29 @@ listener array. If any single listener has been added multiple times to the
listener array for the specified `event`, then `removeListener` must be called
multiple times to remove each instance.
Returns emitter, so calls can be chained.
Because listeners are managed using an internal array, calling this will
change the position indices of any listener registered *after* the listener
being removed. This will not impact the order in which listeners are called,
but it will means that any copies of the listener array as returned by
the `emitter.listeners()` method will need to be recreated.
Returns a reference to the `EventEmitter` so calls can be chained.
### emitter.setMaxListeners(n)
By default EventEmitters will print a warning if more than 10 listeners are
added for a particular event. This is a useful default which helps finding
memory leaks. Obviously not all Emitters should be limited to 10. This function
allows that to be increased. Set to `Infinity` (or `0`) for unlimited.
By default EventEmitters will print a warning if more than `10` listeners are
added for a particular event. This is a useful default that helps finding
memory leaks. Obviously, not all events should be limited to just 10 listeners.
The `emitter.setMaxListeners()` method allows the limit to be modified for this
specific `EventEmitter` instance. The value can be set to `Infinity` (or `0`)
for to indicate an unlimited number of listeners.
Returns emitter, so calls can be chained.
Returns a reference to the `EventEmitter` so calls can be chained.
[`net.Server`]: net.html#net_class_net_server
[`fs.ReadStream`]: fs.html#fs_class_fs_readstream
[`emitter.setMaxListeners(n)`]: #events_emitter_setmaxlisteners_n
[`EventEmitter.defaultMaxListeners`]: #events_eventemitter_defaultmaxlisteners
[emitter.listenerCount]: #events_emitter_listenercount_type
[`emitter.listenerCount()`]: #events_emitter_listenercount_event
[`domain`]: domain.html
[stream]: stream.html

Loading…
Cancel
Save