本节解决上一节遗留的第一个问题 —— “req.on
这里的on
是特定的吗?”
req.on('data', function (chunk) {
})
req.on('end', function () {
})
以上代码的格式其实应该比较熟悉的,和前端用 jQuery 绑定事件类似
$('#btn1').on('click', function (event) {
})
这两点能对应起来,就好说了。
- 观察者模式
- EventEmitter 基本使用
- EventEmitter 继承
- 总结
作为程序猿多少要了解 23 种设计模式,其中观察者模式是非常重要的一个。简单说来,就是定义好监听的操作,然后等待事件的触发。前端开发中,有不少地方能体现观察者模式。最简单的例如绑定事件:
$('#btn1').on('click', function (event) {
alert(1)
})
$('#btn1').on('click', function (event) {
alert(2)
})
比较复杂的例如 vue 中,修改data
之后,会立刻出发视图重新渲染,这也是观察者模式的应用。
nodejs 中的自定义事件也是观察者模式的一种体现,而且自定义事件常见于 nodejs 的各个地方。先看一个简单示例
const EventEmitter = require('events').EventEmitter
const emitter1 = new EventEmitter()
emitter1.on('some', () => {
// 监听 some 事件
console.log('some event is occured 1')
})
emitter1.on('some', () => {
// 监听 some 事件
console.log('some event is occured 2')
})
// 触发 some 事件
emitter1.emit('some')
以上代码中,先引入 nodejs 提供的EventEmitter
构造函数,然后初始化一个实例emitter1
。实例通过on
可监听事件,emit
可以触发事件,事件名称可以自定义,如some
。
自定义事件触发的时候还可传递参数,例如
const emitter = new EventEmitter()
emitter.on('sbowName', name => {
console.log('event occured ', name)
})
emitter.emit('sbowName', 'zhangsan') // emit 时候可以传递参数过去
还有自定义事件的异常捕获,如下形式:
// 例四
const emitter1 = new EventEmitter()
emitter1.on('some', () => {
console.log('11111')
})
emitter1.on('some', () => {
console.log('22222')
throw new Error('自定义错误') // 触发过程中抛出错误
})
emitter1.on('some', () => {
console.log('33333')
})
try {
emitter1.emit('some')
} catch (ex) {
console.log(ex.stack) // 可以捕获到事件执行过程中的错误
}
console.log('after emit')
再次回顾上一节的req.on('data' ...
和req.on('end', ...
,和这里是一样的,就是监听data
和end
两个事件。但是,上文是EventEmitter
实例才有这样的功能,req
并没有看到是EventEmitter
的实例 —— 下文解惑。
上文说到EventEmitter
实例有on
和emit
接口,其实自定义 class 的实例也可以有,只不过需要继承EventEmitter
。使用 ES6 的继承语法很容易实现
// 任何构造函数都可以继承 EventEmitter 的方法 on emit
class Dog extends EventEmitter {
constructor(name) {
super()
this.name = name
}
}
var simon = new Dog('simon')
simon.on('bark', function () {
console.log(this.name, ' barked')
})
setInterval(() => {
simon.emit('bark')
}, 500)
这么说,req.on('data' ...
和req.on('end', ...
中,其实req
的构造函数已经继承了EventEmitter
,因此req
才会有on
接口。
本节介绍了EventEmitter
的使用,并顺带解释了req.on('data' ...
和req.on('end', ...
中的on
。以后只要看到xxx.on()
和xxx.emit()
,就应该想到这里的自定义事件。