You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
function_addListener(target,type,listener,prepend){varm;varevents;varexisting;if(typeoflistener!=='function')thrownewTypeError('"listener" argument must be a function');events=target._events;if(!events){//先判断EventEmitter对象是否存在_events成员函数events=target._events=Object.create(null);target._eventsCount=0;}else{if(events.newListener){target.emit('newListener',type,listener.listener ? listener.listener : listener);events=target._events;}existing=events[type];}if(!existing){// Optimize the case of one listener. Don't need the extra array object.existing=events[type]=listener;++target._eventsCount;}else{if(typeofexisting==='function'){// Adding the second element, need to change to array.existing=events[type]=prepend ? [listener,existing] : [existing,listener];// If we've already got an array, just append.}elseif(prepend){existing.unshift(listener);}else{existing.push(listener);}// Check for listener leakif(!existing.warned){m=$getMaxListeners(target);if(m&&m>0&&existing.length>m){existing.warned=true;constw=newError('Possible EventEmitter memory leak detected. '+`${existing.length}${String(type)} listeners `+'added. Use emitter.setMaxListeners() to '+'increase limit');w.name='MaxListenersExceededWarning';w.emitter=target;w.type=type;w.count=existing.length;process.emitWarning(w);}}}returntarget;}
EventEmitter.prototype.once=functiononce(type,listener){if(typeoflistener!=='function')thrownewTypeError('"listener" argument must be a function');this.on(type,_onceWrap(this,type,listener));returnthis;};
介绍
node
中的事件模块是发布/订阅的一种模式,这个模块比前端中的大量DOM事件简单一些,不存在事件冒泡,也不存在preventDefault()、stopPropagation() stopImmediatePropagation()
这些控制事件传递的方法。它包含了emit,on,once,addListener
等方法。具体的用法可以移步官网源码解析
node
中涉及EventEmitter
的代码位于lib/events.js
,其中的代码也很简单,主要是构造了一个EventEmitter
对象,并且暴露了一些原型方法。源码比较简单,这里只解析一些自己觉得有必要记录的地方。emit
原型方法emit
方法中做了一些参数的初始化以及容错处理,核心部分是根据所传参数个数不同而做的不同处理,代码如下:代码注释只是说,根据所传不同参数个数有相应的处理,处理起来会使速度变快,但是我个人觉得这种处理方式很傻(闭嘴)。且不论对错,先追踪到
emitMany
函数看看(emitNone
,emitOne
,emitTwo
,emitThree
都长得一样):这个函数是触发
on
函数中对不同事件类型定义的回调函数,并将emit
中传入的参数传入回调函数。这里有一个逻辑分支,就是当listener
是函数类型的话,则直接执行,也就是对应下面的简单情形:第二个分支刚开始一直想不到是什么情形下触发的,因为在定义
on
,也就是为事件类型定义监听事件的时候,传入的listener
必须是函数类型的,也就是必然会符合isFn
为true
从而执行第一种逻辑分支。但是当同事对一种事件类型声明多个监听事件时,此时的isFn
就是false
,这种情形代码如下:此时的
handler
如下:源码中有一行代码比较关键:
之所以将
handle
进行拷贝并且执行,主要是为了防止在触发监听器的时候,原始注册的监听器发生了修改,如下面的情形:执行上面这段代码的时候,并不会因为提前删除了
fun2
而报错。对于这篇博文里面提到的
arrayClone
的作用不太认同,里面提出的示例是:这段代码根本不会执行到
arrayClone
中去。(在这一块纠结了好久,断点调试发现根本不符合执行条件)on
和addListener
这两个函数是相同的,用于添加新的监听器。两者都是直接调用的
_addListener
,源码如下:这个函数代码比较简单,在每次添加监听器的时候,都触发
newListener
,所以如果需要在某个事件类型之前执行一些东西,例如:打印出来的就是:
除此之外,就是对
maxListener
的一个限定的判断,比较简单,在此不赘述。once
once
用来限制事件监听器只被执行一次,其源码如下:通过代码可以看出
once
调用的on
方法,并把_onceWrap
作为listener
传过去,最后执行的是onceWrapper
。源码如下:这个函数和
emit
的核心部分是一样的,只是设置了一个fired
字段来标记是否是第一次执行,如果是,则对当前事件进行移除并设置fired
为true
。值得注意的点
Eventemitter
的emit
是同步的这是为了保证正确的事件排序以及避免资源抢夺和逻辑错误。
执行下面这段代码就可以看出来:
打印的分别是:
111 222 333
同时也可以通过使用
setImmediate()
或者process.nextTick()
方法来实现异步。例如:防止死循环调用
如下面代码:
这个例子会触发死循环调用,不断打印出222。因为在监听回调里面不断执行了
emit
进行事件的触发,导致不断循环调用。但是下面这段代码就不会死循环:
因为在
emit
触发事件回调的时候,此时执行emitter.on('test',test)
这行代码的时候,只是在当前的test
这个事件类型中多加了一个事件监听器而已,通过打印test
的监听器数量时:会打印出2
如何继承 eventEmitter
fs
模块继承了eventEmitter
模块,具体调用方式如下:调用比较简单
总结:
node
中的event
模块的源码比较简单,但是一些实现的细节还是值得去深究的,会有很多借鉴的地方The text was updated successfully, but these errors were encountered: