Node.js v8.x 中文文档
目录
- events (事件)
- 给监听器传入参数与
this
- 异步与同步
- 只处理事件一次
- 错误事件
- EventEmitter 类
- 'newListener' 事件
- 'removeListener' 事件
- EventEmitter.listenerCount(emitter, eventName)
- EventEmitter.defaultMaxListeners
- emitter.addListener(eventName, listener)
- emitter.emit(eventName[, ...args])
- emitter.eventNames()
- emitter.getMaxListeners()
- emitter.listenerCount(eventName)
- emitter.listeners(eventName)
- emitter.on(eventName, listener)
- emitter.once(eventName, listener)
- emitter.prependListener(eventName, listener)
- emitter.prependOnceListener(eventName, listener)
- emitter.removeAllListeners([eventName])
- emitter.removeListener(eventName, listener)
- emitter.setMaxListeners(n)
- 给监听器传入参数与
events (事件)#
大多数 Node.js 核心 API 都采用惯用的异步事件驱动架构,其中某些类型的对象(触发器)会周期性地触发命名事件来调用函数对象(监听器)。
例如,net.Server
对象会在每次有新连接时触发事件;fs.ReadStream
会在文件被打开时触发事件;流对象 会在数据可读时触发事件。
所有能触发事件的对象都是 EventEmitter
类的实例。这些对象开放了一个 eventEmitter.on()
函数,允许将一个或多个函数绑定到会被对象触发的命名事件上。事件名称通常是驼峰式的字符串,但也可以使用任何有效的 JavaScript 属性名。
当 EventEmitter
对象触发一个事件时,所有绑定在该事件上的函数都被同步地调用。监听器的返回值会被丢弃。
例子,一个绑定了一个监听器的 EventEmitter
实例。eventEmitter.on()
方法用于注册监听器,eventEmitter.emit()
方法用于触发事件。
const EventEmitter = require('events');class MyEmitter extends EventEmitter {}const myEmitter = new MyEmitter();myEmitter.on('event', () => { console.log('触发了一个事件!');});myEmitter.emit('event');
给监听器传入参数与 this
#
eventEmitter.emit()
方法允许将任意参数传给监听器函数。当一个普通的监听器函数被 EventEmitter
调用时,标准的 this
关键词会被设置指向监听器所附加的 EventEmitter
。
const myEmitter = new MyEmitter();myEmitter.on('event', function(a, b) { console.log(a, b, this); // 打印: // a b MyEmitter { // domain: null, // _events: { event: [Function] }, // _eventsCount: 1, // _maxListeners: undefined }});myEmitter.emit('event', 'a', 'b');
也可以使用 ES6 的箭头函数作为监听器。但是这样 this
关键词就不再指向 EventEmitter
实例:
const myEmitter = new MyEmitter();myEmitter.on('event', (a, b) => { console.log(a, b, this); // 打印: a b {}});myEmitter.emit('event', 'a', 'b');
异步与同步#
EventEmitter
会按照监听器注册的顺序同步地调用所有监听器。所以需要确保事件的正确排序且避免竞争条件或逻辑错误。监听器函数可以使用 setImmediate()
或 process.nextTick()
方法切换到异步操作模式:
const myEmitter = new MyEmitter();myEmitter.on('event', (a, b) => { setImmediate(() => { console.log('这个是异步发生的'); });});myEmitter.emit('event', 'a', 'b');
只处理事件一次#
当使用 eventEmitter.on()
方法注册监听器时,监听器会在每次触发命名事件时被调用。
const myEmitter = new MyEmitter();let m = 0;myEmitter.on('event', () => { console.log(++m);});myEmitter.emit('event');// 打印: 1myEmitter.emit('event');// 打印: 2
使用 eventEmitter.once()
方法时可以注册一个对于特定事件最多被调用一次的监听器。当事件被触发时,监听器会被注销,然后再调用。
const myEmitter = new MyEmitter();let m = 0;myEmitter.once('event', () => { console.log(++m);});myEmitter.emit('event');// 打印: 1myEmitter.emit('event');// 忽略
错误事件#
当 EventEmitter
实例中发生错误时,会触发一个 'error'
事件。这在 Node.js 中是特殊情况。
如果 EventEmitter
没有为 'error'
事件注册至少一个监听器,则当 'error'
事件触发时,会抛出错误、打印堆栈跟踪、且退出 Node.js 进程。
const myEmitter = new MyEmitter();myEmitter.emit('error', new Error('whoops!'));// 抛出错误,并使 Node.js 崩溃
为了防止 Node.js 进程崩溃,可以在使用 domain
模块。(注意,domain
模块已被废弃。)
作为最佳实践,应该始终为 'error'
事件注册监听器。
const myEmitter = new MyEmitter();myEmitter.on('error', (err) => { console.error('有错误');});myEmitter.emit('error', new Error('whoops!'));// 打印: 有错误
EventEmitter 类#
EventEmitter
类由 events
模块定义和开放的:
const EventEmitter = require('events');
当新的监听器被添加时,所有的 EventEmitter 会触发 'newListener'
事件;当移除已存在的监听器时,则触发 'removeListener'
。
'newListener' 事件#
eventName
<any> 要监听的事件的名称listener
<Function> 事件的句柄函数
EventEmitter
实例会在一个监听器被添加到其内部监听器数组之前触发自身的 'newListener'
事件。
注册了 'newListener'
事件的监听器会传入事件名与被添加的监听器的引用。
事实上,在添加监听器之前触发事件有一个微妙但重要的副作用:在'newListener'
回调函数中, 一个监听器的名字如果和已有监听器名称相同, 则在被插入到EventEmitter实例的内部监听器数组时, 该监听器会被添加到其它同名监听器的前面。
const myEmitter = new MyEmitter();// 只处理一次,所以不会无限循环myEmitter.once('newListener', (event, listener) => { if (event === 'event') { // 在开头插入一个新的监听器 myEmitter.on('event', () => { console.log('B'); }); }});myEmitter.on('event', () => { console.log('A');});myEmitter.emit('event');// 打印:// B// A
'removeListener' 事件#
eventName
<any> 事件名listener
<Function> 事件句柄函数
'removeListener'
事件在 listener
被移除后触发。
EventEmitter.listenerCount(emitter, eventName)#
emitter.listenerCount()
代替。A class method that returns the number of listeners for the given eventName
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#
每个事件默认可以注册最多 10 个监听器。单个 EventEmitter
实例的限制可以使用 emitter.setMaxListeners(n)
方法改变。所有 EventEmitter
实例的默认值可以使用 EventEmitter.defaultMaxListeners
属性改变。如果这个值不是正数, 那将抛出 TypeError
错误.
设置 EventEmitter.defaultMaxListeners
要谨慎,因为会影响所有 EventEmitter
实例,包括之前创建的。因而,调用 emitter.setMaxListeners(n)
优先于 EventEmitter.defaultMaxListeners
。
注意,这不是一个硬性限制。EventEmitter
实例允许添加更多的监听器,但会向 stderr
输出跟踪警告,表明检测到一个可能的 EventEmitter 内存泄漏。对于任何单个 EventEmitter
实例,emitter.getMaxListeners()
和 emitter.setMaxListeners()
方法可用于暂时地消除此警告:
emitter.setMaxListeners(emitter.getMaxListeners() + 1);emitter.once('event', () => { // 做些操作 emitter.setMaxListeners(Math.max(emitter.getMaxListeners() - 1, 0));});
--trace-warnings
命令行标志可用于显示此类警告的堆栈跟踪。
触发的警告可以使用 process.on('warning')
检查,还有额外的 emitter
、type
和 count
属性,分别代表事件触发器实例的引用、事件的名称、和附加的监听器的数量。其 name
属性设置为 MaxListenersExceededWarning
。
emitter.addListener(eventName, listener)#
eventName
<any>listener
<Function>
emitter.on(eventName, listener)
的别名。
emitter.emit(eventName[, ...args])#
eventName
<any>...args
<any>
按监听器的注册顺序,同步地调用每个注册到名为 eventName
事件的监听器,并传入提供的参数。
如果事件有监听器,则返回 true
,否则返回 false
。
emitter.eventNames()#
返回一个列出触发器已注册监听器的事件的数组。数组中的值为字符串或符号。
const EventEmitter = require('events');const myEE = new EventEmitter();myEE.on('foo', () => {});myEE.on('bar', () => {});const sym = Symbol('symbol');myEE.on(sym, () => {});console.log(myEE.eventNames());// 打印: [ 'foo', 'bar', Symbol(symbol) ]
emitter.getMaxListeners()#
返回 EventEmitter
当前的最大监听器限制值,该值可以通过 emitter.setMaxListeners(n)
设置或默认为 EventEmitter.defaultMaxListeners
。
emitter.listenerCount(eventName)#
eventName
<any> 正在被监听的事件名
返回正在监听名为 eventName
的事件的监听器的数量。
emitter.listeners(eventName)#
eventName
<any>
返回名为 eventName
的事件的监听器数组的副本。
server.on('connection', (stream) => { console.log('someone connected!');});console.log(util.inspect(server.listeners('connection')));// 打印: [ [Function] ]
emitter.on(eventName, listener)#
eventName
<any> 事件名listener
<Function> 回调函数
添加 listener
函数到名为 eventName
的事件的监听器数组的末尾。不会检查 listener
是否已被添加。多次调用并传入相同的 eventName
和 listener
会导致 listener
被添加与调用多次。
server.on('connection', (stream) => { console.log('有连接!');});
返回一个 EventEmitter
引用,可以链式调用。
默认情况下,事件监听器会按照添加的顺序依次调用。emitter.prependListener()
方法可用于将事件监听器添加到监听器数组的开头。
const myEE = new EventEmitter();myEE.on('foo', () => console.log('a'));myEE.prependListener('foo', () => console.log('b'));myEE.emit('foo');// 打印:// b// a
emitter.once(eventName, listener)#
eventName
<any> 事件名listener
<Function> 回调函数
添加一个单次 listener
函数到名为 eventName
的事件。下次触发 eventName
事件时,监听器会被移除,然后调用。
server.once('connection', (stream) => { console.log('首次调用!');});
返回一个 EventEmitter
引用,可以链式调用。
默认情况下,事件监听器会按照添加的顺序依次调用。emitter.prependOnceListener()
方法可用于将事件监听器添加到监听器数组的开头。
const myEE = new EventEmitter();myEE.once('foo', () => console.log('a'));myEE.prependOnceListener('foo', () => console.log('b'));myEE.emit('foo');// 打印:// b// a
emitter.prependListener(eventName, listener)#
eventName
<any> 事件名listener
<Function> 回调函数
添加 listener
函数到名为 eventName
的事件的监听器数组的开头。不会检查 listener
是否已被添加。多次调用并传入相同的 eventName
和 listener
会导致 listener
被添加与调用多次。
server.prependListener('connection', (stream) => { console.log('有连接!');});
返回一个 EventEmitter
引用,可以链式调用。
emitter.prependOnceListener(eventName, listener)#
eventName
<any> 事件名listener
<Function> 回调函数
添加一个单次 listener
函数到名为 eventName
的事件的监听器数组的开头。下次触发 eventName
事件时,监听器会被移除,然后调用。
server.prependOnceListener('connection', (stream) => { console.log('首次调用!');});
返回一个 EventEmitter
引用,可以链式调用。
emitter.removeAllListeners([eventName])#
eventName
<any>
移除全部或指定 eventName
的监听器。
注意,在代码中移除其他地方添加的监听器是一个不好的做法,尤其是当 EventEmitter
实例是其他组件或模块(如 socket 或文件流)创建的。
返回一个 EventEmitter
引用,可以链式调用。
emitter.removeListener(eventName, listener)#
eventName
<any>listener
<Function>
从名为 eventName
的事件的监听器数组中移除指定的 listener
。
const callback = (stream) => { console.log('有连接!');};server.on('connection', callback);// ...server.removeListener('connection', callback);
removeListener
最多只会从监听器数组里移除一个监听器实例。如果任何单一的监听器被多次添加到指定 eventName
的监听器数组中,则必须多次调用 removeListener
才能移除每个实例。
注意,一旦一个事件被触发,所有绑定到它的监听器都会按顺序依次触发。这意味着,在事件触发后、最后一个监听器完成执行前,任何 removeListener()
或 removeAllListeners()
调用都不会从 emit()
中移除它们。随后的事件会像预期的那样发生。
const myEmitter = new MyEmitter();const callbackA = () => { console.log('A'); myEmitter.removeListener('event', callbackB);};const callbackB = () => { console.log('B');};myEmitter.on('event', callbackA);myEmitter.on('event', callbackB);// callbackA 移除了监听器 callbackB,但它依然会被调用。// 触发是内部的监听器数组为 [callbackA, callbackB]myEmitter.emit('event');// 打印:// A// B// callbackB 被移除了。// 内部监听器数组为 [callbackA]myEmitter.emit('event');// 打印:// A
因为监听器是使用内部数组进行管理的,所以调用它会改变在监听器被移除后注册的任何监听器的位置索引。虽然这不会影响监听器的调用顺序,但意味着由 emitter.listeners()
方法返回的监听器数组副本需要被重新创建。
返回一个 EventEmitter
引用,可以链式调用。
emitter.setMaxListeners(n)#
默认情况下,如果为特定事件添加了超过 10
个监听器,则 EventEmitter
会打印一个警告。此限制有助于寻找内存泄露。但是,并不是所有的事件都要被限为 10
个。emitter.setMaxListeners()
方法允许修改指定的 EventEmitter
实例的限制。值设为 Infinity
(或 0
)表明不限制监听器的数量。
返回一个 EventEmitter
引用,可以链式调用。
免责声明:以上内容(如有图片或视频亦包括在内)有转载其他网站资源,如有侵权请联系删除