Event 模块解析

目录

首先搞清楚一些基础的名词.

1.Emitter(触发器) 某些类型的对象

2.Listener(监听器) 函数

第一类坑是非event模块的

1.箭头函数 this的问题

2. 同步和异步的问题(event模块中的on,once注册都是同步)

2.一个错误事件

第二类坑:event模块中的坑

1. EventEmitter 类 中本身是自带 newListener 和 removeListener 事件的.

2.第二个坑就是emitter.emit(eventName[, ...args])的"arg"参数问题了

3.第三个坑就是emitter.listenerCount(eventName)"返回正在监听的名为 eventName 的事件的监听器的数量。"

4.返回时EventEmitter类的链式连接

5.prependListener 

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的坑.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值