前言
Node.js 使用事件驱动模型,当web server接收到请求,就把它关闭然后进行处理,然后去服务下一个web请求。
当这个请求完成,它被放回处理队列,当到达队列开头,这个结果被返回给用户。
这个模型非常高效可扩展性非常强,因为webserver一直接受请求而不等待任何读写操作。(这也被称之为非阻塞式IO或者事件驱动IO)
在事件驱动模型中,会生成一个主循环来监听事件,当检测到事件时触发回调函数。
如下图示:
event_loop
背景
我们将通过一颗小树苗的养成记来学习一下EventEmitter中一些有趣的东西。
好了,不说了。撸代码。
// 引入 events 模块
const events = require('events')
// 创建 EventEmitter 实例对象
const 小树苗 = new events.EventEmitter()
/**
* 我们的思路是这样的
* 我们现在有一颗小树苗的种子
* 我们把它种到土里
* 然后给它浇水
* 然后给它施肥
* 然后再给它晒晒太阳
* 然后...
* 我们就假装它长大了^_^
*/
/**
* 我们先写一些事件捕获器
*(好吧,叫监听器也好)
* 就好像抓小精灵
* 抓到了,它总该叫一声吧
*/
const 种树捕获器 = () => {
// 在小种子被种到土里一秒钟后, 土地里发出了一声惨绝人寰的尖叫
setTimeout(() => {
console.log('啊,好黑。宝宝被种到土里了')
}, 1000)
}
const 浇水捕获器 = () => {
setTimeout(() => {
console.log('咦, 有好心人给宝宝浇水了')
}, 2500)
setTimeout(() => {
console.log('宝宝发芽了^_^')
}, 4000)
}
const 施肥捕获器 = () => {
setTimeout(() => {
console.log('啊啊啊,好臭啊')
}, 5500)
setTimeout(() => {
console.log('不过宝宝还是长高高了^_^')
}, 7000)
}
const 晒太阳捕获器 = () => {
setTimeout(() => {
console.log('今天阳光好好, 宝宝好开心^_^')
}, 8500)
}
const 长大了捕获器 = () => {
setTimeout(() => {
console.log('嗯。现在, 宝宝已经长大了。')
}, 10000)
setTimeout(() => {
console.log('全剧终')
}, 12000)
}
// 现在,我们把这些事件和小树苗的成长过程关联起来
小树苗.once('播种', 种树捕获器)
小树苗.on('浇水', 浇水捕获器)
小树苗.on('施肥', 施肥捕获器)
小树苗.on('晒太阳', 晒太阳捕获器)
小树苗.on('长大了', 长大了捕获器)
// 好了,让我们开始种树吧^_^
小树苗.emit('播种')
小树苗.emit('浇水')
小树苗.emit('施肥')
小树苗.emit('晒太阳')
小树苗.emit('长大了')
动图看效果:
解释
- 首先,我们写了一些事件监听器(EventListener)
- 然后,我们把事件监听器和相应的事件关联了起来,即为指定事件注册一个监听器
- 最后,我们触发了这些事件
用到的方法
once(event, listener)
为指定事件注册一个单次监听器,即监听器最多只会触发一次,触发后立刻解除该监听器
on(event, listener)
为指定事件注册一个监听器,接受一个字符串 event 和一个回调函数
emit(event, [arg1], [arg2], [...])
按参数的顺序执行每个监听器,如果事件有注册监听返回 true,否则返回 false
没有用到的方法
addListener(event, listener)
为指定事件添加一个监听器到监听器数组的尾部
removeListener(event, listener)
移除指定事件的某个监听器,监听器 必须是该事件已经注册过的监听器
removeAllListeners([event])
移除所有事件的所有监听器, 如果指定事件,则移除指定事件的所有监听器
setMaxListeners(n)
默认情况下, EventEmitters 如果你添加的监听器超过 10 个就会输出警告信息
setMaxListeners 函数用于提高监听器的默认限制的数量
listeners(event)
返回指定事件的监听器数组
上代码:
const events = require('events')
const EventEmitter = events.EventEmitter
const demo = new EventEmitter()
const listener1 = () => {
console.log('connected to listener1')
}
const listener2 = () => {
console.log('connected to listener2')
}
demo.addListener('connection', listener1)
demo.addListener('connection', listener2)
// listenerCount(emitter, event) 返回指定事件的监听器数量
let CountOfListener = EventEmitter.listenerCount(demo, 'connection')
console.log(`监听器个数: ${CountOfListener}`)
demo.emit('connection')
demo.removeListener('connection', listener1)
console.log('移除listener1')
demo.emit('connection')
CountOfListener = EventEmitter.listenerCount(demo, 'connection')
console.log(`监听器个数: ${CountOfListener}`)
// 举个emit传递参数的栗子
demo.addListener('go', (who , source, dest) => {
console.log(`${who}从${source}到${dest}去`)
})
demo.emit('go', '小明', '地上', '天上')
console.log('complete')
运行结果如下:
写在最后
这这这这还能用汉语直接撸代码?!!
没错,JS就是这么神奇。
感谢看到这篇文章的你。
好了,睡觉。_
网友评论