-
Notifications
You must be signed in to change notification settings - Fork 272
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Node.js EventEmitter类源码浅析 #29
Comments
关于初始化空对象的方法那个:
这两个区别是: var a = {}
a.hasOwnProperty; // ƒ hasOwnProperty() { [native code] }
var b = Object.create(null)
b.hasOwnProperty; //undefined |
@jjeejj 嗯嗯是这样的,可能置空它的prototype会更快,不过我简单对比了一下直接读取这两个对象属性的时间貌似区别不大哈哈,还是不太能领会这么用的妙处233 |
两种用法无关乎性能,用 相比于 不会对全局对象(整条原型链)产生任何影响 |
@SirM2z 哦对对有道理!受教受教 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
写在最前
本次尝试浅析Node.js中的EventEmitter模块的事件机制,分析在Node.js中实现发布订阅模式的一些细节。完整Node.js源码点这里。
欢迎关注我的博客,不定期更新中——
EventEmitter
Node.js中对EventEmitter类的实例的运用可以说是贯穿整个Node.js,相信这一点大家已经是很熟悉的了。其中所运用到的发布订阅模式,则是很经典的管理消息分发的一种方式。在这种模式中,发布消息的一方不需要知道这个消息会给谁,而订阅的一方也无需知道消息的来源。使用方式一般如下:
当我们订阅了'event'事件后,可以在任何地方通过
emit('event')
来执行事件回调,EventEmitter相当于一个中介,负责记录都订阅了哪些事件并且触发后的回调是什么,当事件被触发,就将回调一一执行。发布订阅模式
从源码中看下EventEmitter类的是如何实现发布订阅的。
首先我们梳理一下实现这个模式需要的步骤:
初始化空对象
在生成空对象的方式中,一般容易想到的是直接进行赋值空对象即
var a = {};
,Node.js中采用的方式为var a = Object.create(null)
,使用这种方式理论上是应该对对象的属性存取的操作更快,出于好奇作者对这两种方式做了个粗略的对比:打印结果显示出来貌似直接用空对象赋值与通过Object.create的方式并没有很大的性能差异,并且还没有谁一定占了上风,就目前该空对象用来存储注册的监听事件与回调来看,如果直接用{}来初始化this._events性能方面影响也许不大。不过这一点只是个人观点,暂时还并不能领会Node里面如此运用的深意。
添加监听事件,注册回调函数
添加监听者的方法为addListener,同时on是其别名。
如果之前不存在监听事件,则会进入第一个判断内,其中type为事件类型,listener为触发的事件回调。如果之前注册过事件,那么回调函数会添加到回调队列的头或尾。看如下打印结果:
myEmitter实例的_events方法就是我们存储事件与回调的对象,可以看到当我们依次注册事件后,回调会被推到 _events对应key的value中。
触发事件,找出对应回调函数队列,一一执行
在触发的emit函数中,会根据触发时传入参数的多少执行不同的函数:(参数不同直接执行不同的函数,这个操作应该会让性能更好,不过作者没有测试这点)
以emitMany为例看下内部触发实现:
源码中实现了
arrayClone
方法,来复制一份同样的监听函数,再去依次执行副本。个人对这个做法的理解是,当触发当前类型事件后,就锁定需要执行的回调函数队列,否则当触发回调过程中,再去推入新的回调函数,或者删除已有回调函数,容易造成不可预知的问题。删除监听事件
如果回调事件只有一个那么直接删除即可,如果是数组就像之前看到的那样注册了多组对同样事件的监听,就要涉及从数组中删除项的实现。在这里Node自己实现了一个spliceOne函数来代替原生的splice,并且说明其方式比splice快1.5倍。下面是作者进行的简易粗略,不严谨的运行时间比较:
上面做了一个很粗略的运算时间比较,同样是对长度为1000的数组第100项进行删除操作,并且代码运行在chrome浏览器下(版本号61.0.3163.100)node源码中自己实现的方法确实比原生的splice快了一些,不过结果只是一个参考毕竟这个对比很粗略,有兴趣的童鞋可以写一组benchmark来进行对比。
参考资料
最后
源码的边界情况比较多。在这里只做一个相对简单的流程浅析,哪里说明有误欢迎指正~
PS:相关实例源码:https://github.com/Aaaaaaaty/Blog/blob/master/node/event.js
惯例po作者的博客,不定时更新中——
有问题欢迎在issues下交流。
The text was updated successfully, but these errors were encountered: