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--> <!--type=module-->
Many objects in Node.js emit events: a [`net.Server`][] emits an event each Much of the Node.js core API is built around an idiomatic asynchronous
time a peer connects to it, a [`fs.ReadStream`][] emits an event when the file event-driven architecture in which certain kinds of objects (called "emitters")
is opened. All objects which emit events are instances of `events.EventEmitter`. periodically emit named events that cause Function objects ("listeners") to be
You can access this module by doing: `require("events");` called.
Typically, event names are represented by a camel-cased string, however, For instance: a [`net.Server`][] object emits an event each time a peer
there aren't any strict restrictions on that, as any valid property key will be connects to it; a [`fs.ReadStream`][] emits an event when the file is opened;
accepted. 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 All objects that emit events are instances of the `EventEmitter` class. These
is emitted. These functions are called _listeners_. Inside a listener objects expose an `eventEmitter.on()` function that allows one or more
function, `this` refers to the `EventEmitter` that the listener was Functions to be attached to named events emitted by the object. Typically,
attached to. 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');
function MyEmitter() {
EventEmitter.call(this);
}
util.inherits(MyEmitter, EventEmitter);
```javascript const myEmitter = new MyEmitter();
const EventEmitter = require('events'); myEmitter.on('event', function() {
``` console.log('an event occurred!');
});
myEmitter.emit('event');
When an `EventEmitter` instance experiences an error, the typical action is Any object can become an `EventEmitter` through inheritance. The example above
to emit an `'error'` event. Error events are treated as a special case in uses the traditional Node.js style prototypical inheritance using
Node.js. If there is no listener for it, then the default action is to print the `util.inherits()` method. It is, however, possible to use ES6 classes as
a stack trace and exit the program. well:
All EventEmitters emit the event `'newListener'` when new listeners are const EventEmitter = require('events');
added and `'removeListener'` when a listener is removed.
### Inheriting from 'EventEmitter' class MyEmitter extends EventEmitter {}
Inheriting from `EventEmitter` is no different from inheriting from any other const myEmitter = new MyEmitter();
constructor function. For example: 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');
'use strict'; It is possible to use ES6 Arrow Functions as listeners, however, when doing so,
const util = require('util'); the `this` keyword will no longer reference the `EventEmitter` instance:
const EventEmitter = require('events');
function MyEventEmitter() { const myEmitter = new MyEmitter();
// Initialize necessary properties from `EventEmitter` in this instance myEmitter.on('event', (a, b) => {
EventEmitter.call(this); 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
As a best practice, developers should always register listeners for the
`'error'` 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
// Inherit functions from `EventEmitter`'s prototype ## Class: EventEmitter
util.inherits(MyEventEmitter, EventEmitter);
### Class Method: EventEmitter.listenerCount(emitter, event) The `EventEmitter` class is defined and exposed by the `events` module:
Stability: 0 - Deprecated: Use [emitter.listenerCount][] instead. const EventEmitter = require('events');
Returns the number of listeners for a given event. All EventEmitters emit the event `'newListener'` when new listeners are
added and `'removeListener'` when a listener is removed.
### Event: 'newListener' ### Event: 'newListener'
* `event` {String|Symbol} The event name * `event` {String|Symbol} The event name
* `listener` {Function} The event handler function * `listener` {Function} The event handler function
This event is emitted *before* a listener is added. When this event is The `EventEmitter` instance will emit it's own `'newListener'` event *before*
triggered, the listener has not been added to the array of listeners for the a listener is added to it's internal array of listeners.
`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 Listeners registered for the `'newListener'` event will be passed the event
added. 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: 'removeListener'
* `event` {String|Symbol} The event name * `event` {String|Symbol} The event name
* `listener` {Function} The event handler function * `listener` {Function} The event handler function
This event is emitted *after* a listener is removed. When this event is The `'removeListener'` event is emitted *after* a listener is removed.
triggered, the listener has been removed from the array of listeners for the
`event`. ### 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 ### EventEmitter.defaultMaxListeners
[`emitter.setMaxListeners(n)`][] sets the maximum on a per-instance basis. By default, a maximum of `10` listeners can be registered for any single
This class property lets you set it for *all* `EventEmitter` instances, event. This limit can be changed for individual `EventEmitter` instances
current and future, effective immediately. Use with care. using the [`emitter.setMaxListeners(n)`][] method. To change the default
for *all* `EventEmitter` instances, the `EventEmitter.defaultMaxListeners`
property can be used.
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 [`emitter.setMaxListeners(n)`][] still has precedence over Note that this is not a hard limit. The `EventEmitter` instance will allow
`EventEmitter.defaultMaxListeners`. 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) ### emitter.addListener(event, listener)
@ -93,77 +262,72 @@ Alias for `emitter.on(event, listener)`.
### emitter.emit(event[, arg1][, arg2][, ...]) ### 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. Returns `true` if event had listeners, `false` otherwise.
### emitter.getMaxListeners() ### emitter.getMaxListeners()
Returns the current max listener value for the emitter which is either set by Returns the current max listener value for the `EventEmitter` which is either
[`emitter.setMaxListeners(n)`][] or defaults to set by [`emitter.setMaxListeners(n)`][] or defaults to
[`EventEmitter.defaultMaxListeners`][]. [`EventEmitter.defaultMaxListeners`][].
This can be useful to increment/decrement max listeners to avoid the warning ### emitter.listenerCount(event)
while not being irresponsible and setting a too big number.
emitter.setMaxListeners(emitter.getMaxListeners() + 1);
emitter.once('event', () => {
// do stuff
emitter.setMaxListeners(Math.max(emitter.getMaxListeners() - 1, 0));
});
### emitter.listenerCount(type)
* `type` {Value} The type of event * `event` {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) ### 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) => { server.on('connection', (stream) => {
console.log('someone connected!'); 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) ### emitter.on(event, listener)
Adds a listener to the end of the listeners array for the specified `event`. Adds the `listener` function to the end of the listeners array for the
No checks are made to see if the `listener` has already been added. Multiple specified `event`. No checks are made to see if the `listener` has already
calls passing the same combination of `event` and `listener` will result in the been added. Multiple calls passing the same combination of `event` and
`listener` being added multiple times. `listener` will result in the `listener` being added, and called, multiple
times.
server.on('connection', (stream) => { server.on('connection', (stream) => {
console.log('someone connected!'); 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) ### emitter.once(event, listener)
Adds a **one time** listener for the event. This listener is Adds a **one time** `listener` function for the `event`. This listener is
invoked only the next time the event is fired, after which invoked only the next time `event` is triggered, after which it is removed.
it is removed.
server.once('connection', (stream) => { server.once('connection', (stream) => {
console.log('Ah, we have our first user!'); 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]) ### emitter.removeAllListeners([event])
Removes all listeners, or those of the specified event. It's not a good idea to Removes all listeners, or those of the specified `event`.
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). 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) ### emitter.removeListener(event, listener)
Removes a listener from the listener array for the specified event. Removes the specified `listener` from the listener array for the specified
**Caution**: changes array indices in the listener array behind the listener. `event`.
var callback = function(stream) { var callback = function(stream) {
console.log('someone connected!'); 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 listener array for the specified `event`, then `removeListener` must be called
multiple times to remove each instance. 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) ### emitter.setMaxListeners(n)
By default EventEmitters will print a warning if more than 10 listeners are 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 added for a particular event. This is a useful default that helps finding
memory leaks. Obviously not all Emitters should be limited to 10. This function memory leaks. Obviously, not all events should be limited to just 10 listeners.
allows that to be increased. Set to `Infinity` (or `0`) for unlimited. 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 [`net.Server`]: net.html#net_class_net_server
[`fs.ReadStream`]: fs.html#fs_class_fs_readstream [`fs.ReadStream`]: fs.html#fs_class_fs_readstream
[`emitter.setMaxListeners(n)`]: #events_emitter_setmaxlisteners_n [`emitter.setMaxListeners(n)`]: #events_emitter_setmaxlisteners_n
[`EventEmitter.defaultMaxListeners`]: #events_eventemitter_defaultmaxlisteners [`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