Reactor
模式简介
Reactor
模式结构图:
使用Reactor
模式时发生的操作:
首先应用程序接收到I/O
请求时,会将其提交至Event Demultiplexer
(事件多路分解器),让其生成新的I/O
操作。应用程序还会为新的I/O
请求指定一个处理程序,当操作完成时将调用该处理程序。当向Event Demultiplexer
提交新请求后,Event Demultiplexer
会立即将控制权返回给应用程序。当一组I/O
操作完成时,事件多路分解器将该I/O
操作对应的事件推入Event Queue
(事件队列),此时Event Loop
开始遍历其中的项目,对于每个项目调用其对应的处理程序,由于每个I/O
的处理程序是应用程序的一部分,故此时将控制权交给应用程序,由其去执行处理程序,当处理完后再将控制权交还给Event Loop
,Event Loop
再去调用下一个项目对应的处理程序。在处理程序执行过程中可能会请求新的异步操作,从而会导致新的操作被插入到Event Demultiplexer
。当Event Loop
中的所有项目被处理完时,循环将再次阻塞Event Demultiplexer
,当有新事件可用时,Event Demultiplexer
将触发另一个周期。
异步行为: 应用程序会在一个时间点(不阻塞)访问资源,并为该操作提供一个处理程序,当操作完成时,处理程序将在另一个时间点被调用该操作相关的处理程序。
在Node.js
的核心定义模式:
模式(reactor
)通过阻塞来处理I/O
,直到一组被观察资源的新事件可用,然后将每个事件分派到相关联的处理程序来做出反应。
回调模式
回调是
Reactor
模式处理程序的实现。回调是被调用来传播操作结果的函数,这正是我们在处理异步操作时所需要的。它们会替代总是同步执行的return
指令。
CPS
在
js
中,回调是一个作为参数传递给另一个函数的函数,当操作完成时将调用该结果。在函数编程中,这种传播结果的方式称为CPS
。这是一个通用的概念,它并不总是与异步操作相关联。事实上,它只是表示通过将结果传递给另一个函数(回调)而使结果传播,而不是直接返回给调用者。
同步CPS
function add (a, b, callback) {
callback(a+b)
}
console.log('before')
add(1, 2, (result) => {
console.log(result)
})
console.log('after')
输出结果:
异步CPS
function addtionAsync (a, b, callback) {
setTimeout(() => callback(a + b), 100)
}
console.log('before')
addtionAsync(1, 2, result => console.log('Result: ' +result))
console.log('after')
输出结果:
由于setTimeout()
触发异步操作,它不会等待要执行的回调,而是立即返回,将控制权返回给addtionAsync()
,然后再把控制权返回给调用者。在Node.js
中该特性非常重要,因为它会在发送异步请求后立即将控制权返回给事件循环,以处理来自队列的新事件
工作原理
EventEmitter
events
模块只提供一个对象:events.EventEmitter
(调用events.EventEmitter()
方法可以获取EventEmitter类)。EventEmitter
的核心就是事件触发与事件监听器功能的封装EventEmitter
对象如果在实例化时发生错误,会触发error
事件- 对于同步事件,需要先注册后发送(即on方法在emit之前执行)。对于异步事件,由于事件是异步发出的,即便是看起来
emit
在on
之前调用(实际上不是的,只是位置在on
前,执行仍在on
后),但实际上也是先注册后发送。
1. 使用步骤:
- 引入
events
模块:let events = require('events')
- 创建
EventEmitter
对象:let eventEmitter = new events.EventEmitter()
- 使用(注册事件、给事件绑定监听器、移除事件的监听器…)
2. EventEmitter
对象方法
① eventEmitter.on(事件名称,监听器(函数))
- 为指定事件注册一个监听器,接受一个字符串 event 和一个回调函数。
- 当向eventEmitter对象发送事件时(调用
emit
方法绑定事件名称名称),会调用该事件的监听器(函数)
②eventEmitter.emit(事件名称, [args1], [args2], [...])
- 按照注册顺序执行执行每个监听器
- 如果事件有注册监听返回 true,否则返回 false。
- args参数代表了给监听器传入的参数
③ eventEmitter.addListener(事件名称,监听器(函数))
为指定事件添加一个监听器到监听器数组的尾部(即最后执行)
④ eventEmitter.once(事件名称,监听器(函数))
为指定事件注册一个单次监听器(该监听器只触发一次,触发完后移除)
⑤ eventEmitter.removeListener(事件名称,监听器名称(函数名称))
移除指定事件的某个监听器,监听器必须是该事件已经注册过的监听器
⑥ eventEmitter.removeAllListeners([事件名称])
移除所有事件的所有监听器(即没有参数);如果指定事件(即给定参数),则移除指定事件的所有监听器
⑦ eventEmitter.listeners(事件名称)
返回指定事件的监听数组(返回的是函数集合,可取每一个元素进行调用执行)
3. EventEmitter
类方法
events.emitter.listenerCount(eventName)
获取指定事件的监听器个数
4. 事件