Nodejs Events module是一個很重要的元件,主要原因是在asynchronous programming,Node.js在Javascript的語言層面提供了如callback、Promise、async/await等機制,這些機制都是類似於request-response的概念,也就是先發起一個function call,等待function call回應,可以對於notification類型,特別是event driver programming,就必須使用callback方式。在browser的DOM規範中,也有定義類似的介面EventTarget
https://dom.spec.whatwg.org/#interface-eventtarget
interface EventTarget { constructor(); undefined addEventListener(DOMString type, EventListener? callback, optional (AddEventListenerOptions or boolean) options = {}); undefined removeEventListener(DOMString type, EventListener? callback, optional (EventListenerOptions or boolean) options = {}); boolean dispatchEvent(Event event); };
主要就是定義註冊管理使用callback function的介面
event driven programming的特色就是將event透過handler/listener function來處理,並且event的時間點不確定,所以handler/listener callback function的角色是被動的,有什麼event過來就處理什麼event,event可以是新的資料,譬如說網路socket接收到的內容,也可能是狀態的改變,譬如說XMLHttpRequest的progress event。
在瀏覽器的javascript,因為UI有各種IO原始事件(滑鼠、鍵盤),進而在瀏覽器產生對應出衍生的UI事件。在Nodejs更多的IO操作也是透過event傳達狀態改變,例如’open’, ‘ready’等。或是如Readable stream的’data’
在Node.js中,按照習慣,會發出event的object繼承於EventEmitter,透過.on(eventName, eventHandler/Listener) 來接收event,並且eventName建議是以camel case的方式命名,只是Nodejs大部分的event不需要用到第二個字,所以常見的都只是小寫event name
const EventEmitter = require('events'); class MyEmitter extends EventEmitter {} const myEmitter = new MyEmitter(); myEmitter.on('event', (a, b) => { console.log('an event occurred!'); //this === myEmitter }); myEmitter.emit('event', 'a', 'b');
這裡節錄一段官方文件的範例,透過extends EventEmitter方式,使物件具有收發event的能力,emit透過 function argument,傳遞eventName之外的其他資訊。
.on呼叫的callback不應該是async function,並且callback被呼叫的順序是按照註冊的順序被 synchronously呼叫,另外也有一個.once 的API,主要用於handler/listener只一次性處理event,可參考另一篇文的說明
在Node.js中,錯誤處理有兩類,一種是js exception機制,synchronous function call內部透過throw,可以將錯誤傳遞出來,另外一種是callback中帶err argument,但這些都是function call流程很明確的時候。event driven programming中,因為event本身的特性不是線性流程的處理,不能透過上述兩種方式將錯誤帶出,事實上,也可以想成錯誤是不定期(不預期)的時間點,因此也是一種event。
在Node.js中使用event name為’error’的convention,並且Node.js本身有提供’error’ 的default listener: print call stack + exit
另外需注意的是每個event name的event listener預設上限是10個,可在setMaxListeners設定
對於EventEmitter,常用的用法如下
- class XYZ extends EventEmitter
- xyz.on(‘event name’, callback) / xyz.addListener,同一個一樣”callback”可以加多次
- xyz.off / xyz.removeListener(‘event name’, callback),移除最近一次加的”callback”
- xyz.emit(‘event name’, arg1, arg2…)
其中 on = addListener, off = removeListener
以上簡介Node.js events最基本的用法,在後續版本有多一些處理promise async function的API(events.once v11.13.0、captureRejection v12.16.0),以及增加EventTarget interface(v14.5.0)等,考量到相容性,一般就比較少用。
Pingback: WebSocket node.js ws source 整理 – 1 | C++ Essay