知识图解
EventEmitter
- on
- emit
- off
- once
- newListener
1. on和emit
1.1 使用
const EventEmitter = require('events');
const util = require('util');
function Baby() {}
//继承
util.inherits(Baby, EventEmitter);
//创建实例
const baby = new Baby();
//订阅
baby.on('大哭', (...args) => {
console.log(...args);
})
//订阅
baby.on('大哭', (...args) => {
console.log(...args);
})
//发布
baby.emit('大哭', '我饿了', '我渴了')
//=>输出结果
// 我饿了 我渴了
// 我饿了 我渴了
1.2 实现
function EventEmitter() {
this._events = {}
}
EventEmitter.prototype.on = function(eventName, callback) {
//this._events不存在时
if (!this._events) this._events = {};
//判断是否已经存在对应的事件名
if (!this._events[eventName]) {
this._events[eventName] = [callback];
} else {
this._events[eventName].push(callback);
}
}
EventEmitter.prototype.emit = function(eventName, ...args) {
if (!this._events) this._events = {};
//发布
if (this._events[eventName]) {
this._events[eventName].forEach(fn => fn(...args));
}
}
module.exports = EventEmitter;
2. off
2.1 使用
const EventEmitter = require('events');
const util = require('util');
function Baby() {}
//继承
util.inherits(Baby, EventEmitter);
//创建实例
const baby = new Baby();
//订阅
baby.on('大哭', (...args) => {
console.log(...args);
})
function eat() {
console.log('我要吃饭')
}
//订阅
baby.on('大哭', eat)
//取消订阅的
baby.off('大哭', eat)
//发布
baby.emit('大哭', '我饿了')
//=>输出结果
// 我饿了
2.2 实现
EventEmitter.prototype.off = function(eventName, callback) {
if (!this._events) this._events = {};
if (this._events[eventName]) {
this._events[eventName] = this._events[eventName].filter(event => event !== callback);
}
}
3. once
3.1 使用
const EventEmitter = require('events');
const util = require('util');
function Baby() {}
//继承
util.inherits(Baby, EventEmitter);
//创建实例
const baby = new Baby();
//订阅
baby.on('大哭', (...args) => {
console.log(...args);
})
//订阅一次,第一次emit时会执行,后面的emit不会再执行
baby.once('大哭', () => {
console.log('我要吃饭');
})
baby.emit('大哭', '我饿了');
baby.emit('大哭', '我饿了');
//=>输出结果
// 我饿了
// 我要吃饭
// 我饿了
3.2 实现
//实现还是订阅,但是需要调用订阅的回调时销毁回调
EventEmitter.prototype.once = function(eventName, callback) {
if (!this._events) this._events = {};
const once = (...args) => { //箭头函数,以免this指向出问题
callback(...args);
this.off(eventName, once); //这里需要销毁的是once了,因为on的时候是once
}
this.on(eventName, once)
}
其实这样的once还不够完整,可能出现调用了once, 然后调用off,这样的话,会产生调用一次once的情况,源码中可是一次都没调
once修改
EventEmitter.prototype.once = function(eventName, callback) {
if (!this._events) this._events = {};
const once = (...args) => {
callback(...args);
this.off(eventName, once)
}
once.l = callback; //防止once了以后用调用off方法,这个需要用这个标识来清除掉
this.on(eventName, once)
}
off修改
EventEmitter.prototype.off = function(eventName, callback) {
if (!this._events) this._events = {};
if (this._events[eventName]) {
this._events[eventName] = this._events[eventName].filter(event => event !== callback && event.l !== callback);
}
}
4. newListener
newListener除自己外订阅的时候就会回调callback, 传递调用类型
4.1 使用
const EventEmitter = require('events');
const util = require('util');
function Baby() {}
//继承
util.inherits(Baby, EventEmitter);
//创建实例
const baby = new Baby();
baby.on('newListener', (type) => {
console.log('newListener:', type)
})
//订阅
baby.on('大哭', (...args) => {
console.log(...args);
})
baby.once('大哭', () => {
console.log('我要吃饭');
});
//=>输出
// newListener: 大哭
// newListener: 大哭
4.2 实现
EventEmitter.prototype.on = function(eventName, callback) {
//调用on的时候没有 _events属性,就动态增加一个
if (!this._events) this._events = {};
//newListenr在每次on的时候触发
if (eventName !== 'newListener') {
this.emit('newListener', eventName);
}
//判断是有已经有对应的事件名
if (!this._events[eventName]) {
this._events[eventName] = [callback];
} else {
this._events[eventName].push(callback);
}
}
全部代码
function EventEmitter() {
this._events = {}; //实例属性
}
//订阅
EventEmitter.prototype.on = function(eventName, callback) {
//调用on的时候没有 _events属性,就动态增加一个
if (!this._events) this._events = {};
//newListenr在每次on的时候触发
if (eventName !== 'newListener') {
this.emit('newListener', eventName);
}
//判断是有已经有对应的事件名
if (!this._events[eventName]) {
this._events[eventName] = [callback];
} else {
this._events[eventName].push(callback);
}
}
//发布
EventEmitter.prototype.emit = function(eventName, ...args) {
//防止先发布的时候this._events为空报错
if (!this._events) this._events = {};
this._events[eventName].forEach(event => event(...args));
}
//取消订阅
EventEmitter.prototype.off = function(eventName, callback) {
if (!this._events) this._events = {};
if (this._events[eventName])
this._events[eventName] = this._events[eventName].filter(event => event !== callback && event.l !== callback);
}
//订阅一次
EventEmitter.prototype.once = function(eventName, callback) {
if (!this._events) this._events = {};
const once = (...args) => {
callback(...args);
this.off(eventName, once)
}
once.l = callback; //防止once了以后用调用off方法,这个需要用这个标识来清除掉
this.on(eventName, once)
}
module.exports = EventEmitter;