前言
Node.js 使用事件驅(qū)動模型,當(dāng)web server接收到請求,就把它關(guān)閉然后進(jìn)行處理,然后去服務(wù)下一個web請求。
當(dāng)這個請求完成,它被放回處理隊列,當(dāng)?shù)竭_(dá)隊列開頭,這個結(jié)果被返回給用戶。
這個模型非常高效可擴展性非常強,因為webserver一直接受請求而不等待任何讀寫操作。(這也被稱之為非阻塞式IO或者事件驅(qū)動IO)
在事件驅(qū)動模型中,會生成一個主循環(huán)來監(jiān)聽事件,當(dāng)檢測到事件時觸發(fā)回調(diào)函數(shù)。
如下圖示:
背景
我們將通過一顆小樹苗的養(yǎng)成記來學(xué)習(xí)一下EventEmitter中一些有趣的東西。
好了,不說了。擼代碼。
// 引入 events 模塊
const events = require('events')
// 創(chuàng)建 EventEmitter 實例對象
const 小樹苗 = new events.EventEmitter()
/**
* 我們的思路是這樣的
* 我們現(xiàn)在有一顆小樹苗的種子
* 我們把它種到土里
* 然后給它澆水
* 然后給它施肥
* 然后再給它曬曬太陽
* 然后...
* 我們就假裝它長大了^_^
*/
/**
* 我們先寫一些事件捕獲器
*(好吧,叫監(jiān)聽器也好)
* 就好像抓小精靈
* 抓到了,它總該叫一聲吧
*/
const 種樹捕獲器 = () => {
// 在小種子被種到土里一秒鐘后, 土地里發(fā)出了一聲慘絕人寰的尖叫
setTimeout(() => {
console.log('啊,好黑。寶寶被種到土里了')
}, 1000)
}
const 澆水捕獲器 = () => {
setTimeout(() => {
console.log('咦, 有好心人給寶寶澆水了')
}, 2500)
setTimeout(() => {
console.log('寶寶發(fā)芽了^_^')
}, 4000)
}
const 施肥捕獲器 = () => {
setTimeout(() => {
console.log('啊啊啊,好臭啊')
}, 5500)
setTimeout(() => {
console.log('不過寶寶還是長高高了^_^')
}, 7000)
}
const 曬太陽捕獲器 = () => {
setTimeout(() => {
console.log('今天陽光好好, 寶寶好開心^_^')
}, 8500)
}
const 長大了捕獲器 = () => {
setTimeout(() => {
console.log('嗯?,F(xiàn)在, 寶寶已經(jīng)長大了。')
}, 10000)
setTimeout(() => {
console.log('全劇終')
}, 12000)
}
// 現(xiàn)在,我們把這些事件和小樹苗的成長過程關(guān)聯(lián)起來
小樹苗.once('播種', 種樹捕獲器)
小樹苗.on('澆水', 澆水捕獲器)
小樹苗.on('施肥', 施肥捕獲器)
小樹苗.on('曬太陽', 曬太陽捕獲器)
小樹苗.on('長大了', 長大了捕獲器)
// 好了,讓我們開始種樹吧^_^
小樹苗.emit('播種')
小樹苗.emit('澆水')
小樹苗.emit('施肥')
小樹苗.emit('曬太陽')
小樹苗.emit('長大了')
動圖看效果:
解釋
- 首先,我們寫了一些事件監(jiān)聽器(EventListener)
- 然后,我們把事件監(jiān)聽器和相應(yīng)的事件關(guān)聯(lián)了起來,即為指定事件注冊一個監(jiān)聽器
- 最后,我們觸發(fā)了這些事件
用到的方法
once(event, listener)
為指定事件注冊一個單次監(jiān)聽器,即監(jiān)聽器最多只會觸發(fā)一次,觸發(fā)后立刻解除該監(jiān)聽器
on(event, listener)
為指定事件注冊一個監(jiān)聽器,接受一個字符串 event 和一個回調(diào)函數(shù)
emit(event, [arg1], [arg2], [...])
按參數(shù)的順序執(zhí)行每個監(jiān)聽器,如果事件有注冊監(jiān)聽返回 true,否則返回 false
沒有用到的方法
addListener(event, listener)
為指定事件添加一個監(jiān)聽器到監(jiān)聽器數(shù)組的尾部
removeListener(event, listener)
移除指定事件的某個監(jiān)聽器,監(jiān)聽器 必須是該事件已經(jīng)注冊過的監(jiān)聽器
removeAllListeners([event])
移除所有事件的所有監(jiān)聽器, 如果指定事件,則移除指定事件的所有監(jiān)聽器
setMaxListeners(n)
默認(rèn)情況下, EventEmitters 如果你添加的監(jiān)聽器超過 10 個就會輸出警告信息
setMaxListeners 函數(shù)用于提高監(jiān)聽器的默認(rèn)限制的數(shù)量
listeners(event)
返回指定事件的監(jiān)聽器數(shù)組
上代碼:
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) 返回指定事件的監(jiān)聽器數(shù)量
let CountOfListener = EventEmitter.listenerCount(demo, 'connection')
console.log(`監(jiān)聽器個數(shù): ${CountOfListener}`)
demo.emit('connection')
demo.removeListener('connection', listener1)
console.log('移除listener1')
demo.emit('connection')
CountOfListener = EventEmitter.listenerCount(demo, 'connection')
console.log(`監(jiān)聽器個數(shù): ${CountOfListener}`)
// 舉個emit傳遞參數(shù)的栗子
demo.addListener('go', (who , source, dest) => {
console.log(`${who}從${source}到${dest}去`)
})
demo.emit('go', '小明', '地上', '天上')
console.log('complete')
運行結(jié)果如下:
寫在最后
這這這這還能用漢語直接擼代碼??。?/p>
沒錯,JS就是這么神奇。
感謝看到這篇文章的你。
好了,睡覺。_