NodeJS 之 EventEmitter

前言

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ù)。

如下圖示:


event_loop

詳細(xì)描述請大家移步這里

背景

我們將通過一顆小樹苗的養(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('長大了')

動圖看效果:

解釋

  1. 首先,我們寫了一些事件監(jiān)聽器(EventListener)
  2. 然后,我們把事件監(jiān)聽器和相應(yīng)的事件關(guān)聯(lián)了起來,即為指定事件注冊一個監(jiān)聽器
  3. 最后,我們觸發(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就是這么神奇。

感謝看到這篇文章的你。
好了,睡覺。_

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,991評論 19 139
  • https://nodejs.org/api/documentation.html 工具模塊 Assert 測試 ...
    KeKeMars閱讀 6,416評論 0 6
  • 本文包括:1、Listener簡介2、Servlet監(jiān)聽器3、監(jiān)聽三個域?qū)ο髣?chuàng)建和銷毀的事件監(jiān)聽器4、監(jiān)聽三個域?qū)?..
    廖少少閱讀 6,132評論 6 28
  • 毫無疑問,nodeJS改變了整個前端開發(fā)生態(tài)。本文通過分析nodeJS當(dāng)中events模塊源碼,由淺入深,動手實現(xiàn)...
    LucasHC閱讀 1,877評論 3 17
  • 蒙蒙細(xì)雨,輕舟載人,青石小巷,恰好相遇。撐傘的我,躲雨的你。無意一撇,緣結(jié)于此。風(fēng)雨同舟,君子之交。木青幕府。我在...
    千詭閱讀 304評論 0 0