目录
2. 同步和异步的问题(event模块中的on,once注册都是同步)
1. EventEmitter 类 中本身是自带 newListener 和 removeListener 事件的.
2.第二个坑就是emitter.emit(eventName[, ...args])的"arg"参数问题了
3.第三个坑就是emitter.listenerCount(eventName)"返回正在监听的名为 eventName 的事件的监听器的数量。"
6.emitter.removeListener和emitter.removeAllListeners的
7.emitter.rawListeners(eventName)
还有最后一个promise的等待以后再来详说,还剩下一个error触发和一个promise的坑.
建议你看完全部的Event API后 ,然后又疑惑再来看这个,这篇不是小白篇,而且我个人觉得,小白篇意义也不大,太多方法了.你茫然的看别人半忽悠,半坑的指导真的没有意义.
首先搞清楚一些基础的名词.
1.Emitter(触发器) 某些类型的对象
2.Listener(监听器) 函数
两者之间的关系是" 其中某些类型的对象(又称触发器,Emitter)会触发命名事件来调用函数(又称监听器,Listener)。"
1234564789接下去是会踩到的坑
第一类坑是非event模块的
1.箭头函数 this的问题
eventEmitter.emit()
方法可以传任意数量的参数到监听器函数。 当监听器函数被调用时, this
关键词会被指向监听器所绑定的 EventEmitter
实例。也可以使用 ES6 的箭头函数作为监听器。但 this
关键词不会指向 EventEmitter
实例。
2. 同步和异步的问题(event模块中的on,once注册都是同步)
EventEmitter
以注册的顺序同步地调用所有监听器。 这样可以确保事件的正确排序,并有助于避免竞态条件和逻辑错误。 当适当时,监听器函数可以使用 setImmediate()
和 process.nextTick()
方法切换到异步的操作模式
2.一个错误事件
当 EventEmitter
实例出错时,应该触发 'error'
事件。 这些在 Node.js 中被视为特殊情况。
如果没有为 'error'
事件注册监听器,则当 'error'
事件触发时,会抛出错误、打印堆栈跟踪、并退出 Node.js 进程。
作为最佳实践,应该始终为 'error'
事件注册监听器。
第二类坑:event模块中的坑
1. EventEmitter 类 中本身是自带 newListener 和 removeListener 事件的.
.关于 newListener 事件,有一个坑
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
注册用一个"event"事件,在"newLisstener"事件中,那么会先执行"newListener"事件中的注册事件.
2.第二个坑就是emitter.emit(eventName[, ...args])的"arg"参数问题了
const EventEmitter = require('events');
const myEmitter = new EventEmitter();
// 第一个监听器。
myEmitter.on('event', function firstListener() {
console.log('第一个监听器');
});
// 第二个监听器。
myEmitter.on('event', function secondListener(arg1, arg2) {
console.log(`第二个监听器中的事件有参数 ${arg1}、${arg2}`);
});
// 第三个监听器
myEmitter.on('event', function thirdListener(...args) {
const parameters = args.join(', ');
console.log(`第三个监听器中的事件有参数 ${parameters}`);
});
console.log(myEmitter.listeners('event'));
myEmitter.emit('event', 1, 2, 3, 4, 5);
// Prints:
// [
// [Function: firstListener],
// [Function: secondListener],
// [Function: thirdListener]
// ]
// 第一个监听器
// 第二个监听器中的事件有参数 1、2
// 第三个监听器中的事件有参数 1, 2, 3, 4, 5
事件的注册时这样一个形式,
(1)先on注册事件,同时留下回调函数.
(2)再用emit去触发.
(3)当emit触发时是去调用回调函数的
3.第三个坑就是emitter.listenerCount(eventName)"返回正在监听的名为 eventName
的事件的监听器的数量。"
菜鸟一搜千篇一律就是14年脚本之家给出的答案
const EventEmitter = require('events');
const myEE = new EventEmitter();
myEE.on('foo', () => {
console.log(myEE.listenerCount("bar"))
console.log(myEE.listenerCount("sym"))
console.log(myEE.listenerCount("foo"))
});
myEE.on('foo', () => {
console.log(myEE.listenerCount("foo"))
});
myEE.on('foo', () => {
console.log(myEE.listenerCount("foo"))
});
myEE.on('bar', () => {
console.log(myEE.listenerCount("foo"))
});
const sym = Symbol('symbol');
myEE.on(sym, () => {});
console.log(myEE.eventNames());
在注册完后,如果有回调函数就是Listener,在你用emit触发同一事件后,他是一样的.比如,所有的foo就是3.而sym却没有(没有Listener),bar就是1.
4.返回时EventEmitter类的链式连接
const EventEmitter = require('events');
const myEE = new EventEmitter();
const myEE1 = myEE.on('foo', () => {
console.log('a');
myEE1.emit("twice")
}).on("twice",()=>{
console.log("链式链接")
})
myEE.prependListener('foo', () => console.log('b'));
myEE.emit('foo');
// 打印:
// b
// a
// 链式链接
const myEE = new EventEmitter(); EventEmitter是从events模块中继承过来的.
myEE本身自个就是一个大个EventEmitter类.或许我应该写成
const myEE1 = myEE.on('foo', () => {
console.log('a');
myEE1.emit("twice")
})
myEE1.on("twice",()=>{
console.log("链式链接")
})
其实你可以直接这么干
const EventEmitter = require('events');
const myEE = new EventEmitter().on('foo', () => {
console.log('a');
})
myEE.prependListener('foo', () => console.log('b'));
myEE.emit('foo');
// 打印:
// b
// a
5.prependListener
当prependListener,prependOnceListener,once,on 都是一样的注册(v.)事件.只不过添加数组的方式不一样罢了.
const EventEmitter = require('events');
const myEE = new EventEmitter();
const sym = Symbol('symbol');
myEE.on(sym, () => {});
console.log(myEE.eventNames());
myEE.prependListener("bar", ()=>{
console.log(myEE.eventNames())
});
myEE.prependOnceListener("foo",()=>{
console.log(myEE.eventNames())
} );
console.log(myEE.eventNames());
myEE.emit("foo");
myEE.emit("bar");
// [ Symbol(symbol) ]
// [ 'bar', 'foo', Symbol(symbol) ]
// [ 'bar', Symbol(symbol) ]
// [ 'bar', Symbol(symbol) ]
而且,当你emit()的时候,这些都是已经注册完毕了.等待执行.
6.emitter.removeListener和emitter.removeAllListeners的
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
一个人出门去旅游,发现手机不好,决定换手机,他在自己的这个手机上用淘宝买了matepro30.但是要拿到手机总要等待他回家吧,不可能说旅旅游,别人送过来,这谁知道,你明天在哪里.那么这也是这样一个情况.
7.emitter.rawListeners(eventName)
const EventEmitter = require('events');
const emitter = new EventEmitter();
emitter.once('log', () => console.log('只记录一次'));
emitter.once('bar', () => console.log('只记录一次bar'));
// 返回一个数组,包含了一个封装了 `listener` 方法的监听器。
const listeners = emitter.rawListeners('log');
listeners[1] = emitter.rawListeners("bar")[0];
const logFnWrapper = listeners[0];
// 打印 “只记录一次”,但不会解绑 `once` 事件。
logFnWrapper.listener();
// 打印 “只记录一次”,且移除监听器。
logFnWrapper();
emitter.on('log', () => console.log('持续地记录'));
// 返回一个数组,只包含 `.on()` 绑定的监听器。
const newListeners = emitter.rawListeners('log');
// 打印两次 “持续地记录”。
newListeners[0].listener();
emitter.emit('log');
<--
TypeError: newListeners[0].listener is not a function
at Object.<anonymous> (C:\Users\zhang\PhpstormProjects\untitled\1.js:23:17)
at Module._compile (internal/modules/cjs/loader.js:945:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:962:10)
at Module.load (internal/modules/cjs/loader.js:798:32)
at Function.Module._load (internal/modules/cjs/loader.js:711:12)
at Function.Module.runMain (internal/modules/cjs/loader.js:1014:10)
-->
只有once注册有listener,logFnWrapper.listener();打印 “只记录一次”,不会解绑 `once` 事件。
const listeners = emitter.rawListeners('log')[0];
// 打印 “只记录一次”,但不会解绑 `once` 事件。
listeners.listener();
// 打印 “只记录一次”,且移除监听器。
listeners();
直接这样就可以了.
还有最后一个promise的等待以后再来详说,还剩下一个error触发和一个promise的坑.