NodeJs 深入浅出之旅:异步 I/O (中)🐉
监听器
此文是承接上文《NodeJs深入浅出之旅:异步I/O (上)》的,所以对于监听器的介绍可以查看之前的内容,或者去API中查看说明
事件监听器模式是一种广泛用于异步编程的模式,是回调函数的事件化,又称发布/订阅模式。
Node 自身提供的 events 事件触发器模块是发布/订阅模式的一个简单实现。
所有触发事件的对象都是
EventEmitter
类的实例。
监听器只监听一次
可以设置监听器为once()
,这样监听就可以只调用一次,不会过多调用。一旦事件被触发,则监听器就会被注销然后被调用。
这种方法对于某些只需要执行一次的查询时效果很明显,比如 SQL 在进行查询时,新到来的相同调用只需在队列中等待数据就绪即可,一旦查询结束,得到的结果可以被这些调用共同使用。这种方式能节省重复的调用产生的开销。 由于 Node 单线程执行的原因,此处也无须担心状态同步问题。
结果:
此监听器方法可以在读取文件数据时减少读取次数
读取方法设置在 IOcode/index.js 中
在这里定义readTxt
读取方法时,设置了Promise
,这样时为了之后调用时获取返回值更加简洁方便,如果出现报错或者正确的返回结果也可以直接使用.then
获取。 (PS:因为工作不能打包,还要兼容 IE9,所以根本用不了 ES6。 只能自学期间时不时添加一下,也只有平时多练习才能熟练使用,惨😭)
入口函数: 调用时使用require
将 IOcode/index.js 导入到入口文件中
结果:
监听器 error 事件
<font color=#f00 size=2 >为了处理异常,EventEmitter
对象对error
事件进行了特殊处理。在Node.js
中被视为特殊情况</font>
如果运行期间的错误触发了error
事件,EventEmitter
回检查是否对error
事件添加过监听器。 如果添加了,这个错误将会交由该监听器处理, 否则这个错误将会作为异常抛出。 如果外部没有捕获这个异常,会引起线程退出。
一个健壮的EventEmitter
实例应该对error
事件做处理。
如果只是发布错误, 异常会抛出,打印堆栈跟踪,然后进程结束
如果设置了error
错误监听器,会转入监听器处理错误,然后进程可以走下去
移除监听器 removeListener
监听器也可以主动进行移除,移除的命令是removeListener
或者removeAllListeners
removeListener
移除指定监听器,removeAllListeners
移除所有监听器。
参考:http://nodejs.cn/api/events.html#events_event_removelistener
如下面的例子,statusChange
方法已经被removeListener
在myEmitter
监听器当中移除,在emit
调用read
时,是不会被触发的。
例子:
移除监听器大多数使用的情况是在项目中有很多监听器,其他的某些监听器对你是不需要的,但是冒然删除并不合适,可以使用removeListener
的方式来移除特定的监听器。
多异步之间的协作方案
事件发布/订阅模式有其优点。 利用高阶函数
,侦听器作为回调函数可以随意添加和删除,这能够帮助开发者轻松处理随时可能添加的业务逻辑,也可以隔离业务逻辑,保持业务逻辑单元的职责单一。
一般而言,事件与侦听器是一对多的关系,但是在异步编程时,可能会出现事件与侦听器是多对一的情况。 比如一个业务逻辑依赖多个通过回调或事件传递的结果。
例子: 一个方法A
的变量a
改变需要在方法B
和方法C
都执行后才能进行 1、定义方法 A
2、定义一个高阶函数after
,然后定义一个done
方法为after
的返回函数,将方法 A 传入回调函数当中,设置times
次数为 2。
以上的意义在于当监听器监听到done
被调用时,可以将传入的key
和value
加入results
当中,然后根据results
内的属性名称数量是否等于设定的times次数
来判断方法A
是否执行
3、定义需要的先决方法B、C
然后执行 B 和 C, A 的执行将会在 C 方法调用后才会执行
结果:
当然了,在多异步之间的协作时,也可以使用EventProxy
。 这是一个很轻量的工具,但是能有效的解决高并发大流量的控制。
安装:
cnpm install eventproxy
或者yarn add eventproxy
调用:
var EventProxy = require('eventProxy');
参考文章:《eventProxy 解决回调坑 (Node.js)》
示例:EventProxy
提供了一个all()
方法来订阅多个事件,需要每个事件都被触发后,侦听器才会执行
EventProxy
在事件发布/订阅模式的基础上还完善了异常处理。 使用fail()
方法将可以监听事件中的错误
在异步编程解决方案还有 Promise/Deferred 模式和流程控制库...👻
版权声明: 本文为 InfoQ 作者【空城机】的原创文章。
原文链接:【http://xie.infoq.cn/article/a44bc7e80a3a35b4af1d07be9】。
本文遵守【CC BY-NC】协议,转载请保留原文出处及本版权声明。
评论