博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
发布订阅模式还不会??戳这里,50行核心代码,手把手教你学会
阅读量:4086 次
发布时间:2019-05-25

本文共 3325 字,大约阅读时间需要 11 分钟。

小插曲

事件

  • 建议大家看下官网中events事件的描述
  • 发布订阅模式定义了一种一对多的依赖关系
  • 在Node中EventEmitter开放on(事件名,回调函数)用于订阅事件
  • emit(事件名)用于发布事件,可能对应多个订阅事件,让订阅事件依次执行

不明白?没关系。举个最简单例子,女人失恋了会哭,还会找新男朋友,在这里哭和找男朋友相当于订阅女人失恋的回调,什么时候执行呢?当发布女人失恋这件事的时候,说的这么抽象,直接来一段代码吧

 

 

 

  • 是不是很简单,只有发布这个事件时候,被订阅的事件才会依次执行,形成一对多的依赖关系。接下来直接写源码实现

思路构建

  • 我们想构造一个类似这样的对象 {"失恋":[cry,findBoy]},当事件发布的时候,让数组中对应的函数依次执行,就实现了这样的效果
  • 先讲个小知识点 {}和Object.create(null)区别。 {}有作用链,通过Object.create(null)创造的空对象没有作用链,给大家演示下,其它就没啥区别。源码就是这样写(逼格高)

 

 

 

实现events模块

1、on和emit 两个核心方法

  • 源码实现
// 声明EventEmitter事件发生器构造函数function EventEmitter() {    this._events = Object.create(null);}//on 订阅方法实现  因为在实例上调用,所以写在原型上EventEmitter.prototype.on = function(type,callback){    // 如果实例不存在则创建一个空对象,Object.create(null)没有链    if(!this._events) {        this._events = Object.create(null);    }    if(this._events[type]){ //如果失恋有对应的值,直接往数组push        this._events[type].push(callback)    }else { //第一次订阅,没有失恋,就声明{失恋:[cry]}        this._events[type] = [callback];    }};// emit方法实现EventEmitter.prototype.emit = function(type){    if(this._events[type]){ //{失恋:[cry,eat]} 如果失恋对应有值,依次执行里面的方法        this._events[type].forEach(fn=>fn())    }};module.exports = EventEmitter复制代码
  • 十几行代码就实现核心功能,这么简单?对 就是这么简单,赶快来测试下吧

 

 

 

2、removeListener 取消订阅事件,失恋了不想哭了,所以我们提供个移除监听的方法

  • 比较简单,直接上代码吧看的直接
// 移除订阅事件的方法EventEmitter.prototype.removeListener = function(type,callback){    if(this._events[type]){        // 返回false就表示不要了,用filter实现去重        this._events[type] = this._events[type].filter(fn=>fn!==callback)    }};复制代码
  • 测试下吧,失恋了不想哭了
  • 完美实现,是不是很激动。

3、removeAllListeners移除全部的监听器,与removeListener相对应

// removeAllListeners 移除所有的监听者EventEmitter.prototype.removeAllListeners = function(){//简单粗暴,直接赋值空对象 {}    this._events = Object.create(null);};复制代码
  • 测试下,失恋了既不想哭,也不想找对象,什么也不打印就对拉

 

 

 

4、扩展once方法 我们希望哭的事件 多次发布emit时候只执行一次,也就代表执行一次后需要将事件从对应关系中移除掉。

// once实现EventEmitter.prototype.once = function(type,callback,flag){    // 先绑定 调用后再删除,运用了one函数 {失恋:one}    let one = (...args)=> {        callback(...args);        this.removeListener(type, one);    }    //自定义属性 因为实例中没有one属性    one.l = callback;    this.on(type,one)};// 移除订阅事件的方法EventEmitter.prototype.removeListener = function(type,callback){    if(this._events[type]){        // 返回false就表示不要了,用filter实现去重        this._events[type] = this._events[type].filter(fn=>fn!==callback && fn.l!==callback)    }};复制代码
  • 你可能会疑惑为什么声明一个wrap函数,设想下,不然你告诉我怎么先绑定一次,在移除。很多人可能都会这么写
  • 错误例子 错误例子 错误例子(重要事情说三遍)
// - 错误例子 错误例子 错误例子(重要事情说三遍)//你可能会这么写,但刚绑定就移除拉,体会这意思了吧EventEmitter.prototype.once = function(type,callback){//先绑定在移除    this.on(type,callback);    this.removeListener(type,callback)};复制代码
  • 测试下吧,一步一个脚印

 

 

 

5、newListener方法。当cry添加到内部监听数组({失恋:[cry]})之前,会触发自身的'newListener'事件

  • 没听懂?我们先来看官方的用法

简单说就是可以监控到订阅的事件类型,上源码看下如何实现

//on 订阅方法实现  因为在实例上调用,所以写在原型上EventEmitter.prototype.on = function(type,callback){    // 如果实例不存在则创建一个空对象,Object.create(null)没有链    if(!this._events) {        this._events = Object.create(null);    }    if(type!=="newListener"){        if(this._events["newListener"]){            this._events["newListener"].forEach(fn=>fn(type))        }    }    if(this._events[type]){ //如果失恋有对应的值,直接往数组push        this._events[type].push(callback)    }else { //第一次订阅,没有失恋,就声明{失恋:[cry]}        this._events[type] = [callback];    }};复制代码
  • 测试下吧

 

 

 

看到这里,基本方法都实现了。不常用就不解释拉。

作者:言sir
链接:https://juejin.im/post/5b338118e51d4558a75e9921
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的文章
剑指offer算法题分析与整理(三)
查看>>
JVM并发机制探讨—内存模型、内存可见性和指令重排序
查看>>
WAV文件解析
查看>>
WPF中PATH使用AI导出SVG的方法
查看>>
QT打开项目提示no valid settings file could be found
查看>>
java LinkedList与ArrayList迭代器遍历和for遍历对比
查看>>
所谓的进步和提升,就是完成认知升级
查看>>
如何用好碎片化时间,让思维更有效率?
查看>>
No.182 - LeetCode1325 - C指针的魅力
查看>>
带WiringPi库的交叉笔译如何处理二之软链接概念
查看>>
Java8 HashMap集合解析
查看>>
自定义 select 下拉框 多选插件
查看>>
Linux常用统计命令之wc
查看>>
fastcgi_param 详解
查看>>
搞定Java面试中的数据结构问题
查看>>
React Native(一):搭建开发环境、出Hello World
查看>>
Winform多线程
查看>>
Spring AOP + Redis + 注解实现redis 分布式锁
查看>>
poj 1976 A Mini Locomotive (dp 二维01背包)
查看>>
《计算机网络》第五章 运输层 ——TCP和UDP 可靠传输原理 TCP流量控制 拥塞控制 连接管理
查看>>