node中的发布订阅(EventEmitter)

知识图解

在这里插入图片描述

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;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值