淺談JS和Nodejs中的事件驅(qū)動(dòng)
事件驅(qū)動(dòng)和發(fā)布-訂閱
事件驅(qū)動(dòng)架構(gòu)是建立在軟件開(kāi)發(fā)中一種通用模式上的,這種模式被稱(chēng)為發(fā)布-訂閱或觀察者模式。
在事件驅(qū)動(dòng)架構(gòu)中,至少有兩個(gè)參與者:主題(subject)和觀察者(observer)。
主題就像調(diào)頻收音機(jī)一樣,向有興趣收聽(tīng)該主題所說(shuō)內(nèi)容的觀察者進(jìn)行廣播。
觀察者可能只有一個(gè),也可能有一百個(gè),這都沒(méi)有關(guān)系,只要主題有一些要廣播的消息就夠了。
請(qǐng)記住,事件驅(qū)動(dòng)、發(fā)布-訂閱和觀察者模式在實(shí)踐中不是一回事,但在理想情況下,它們使用相同的方法:一個(gè)實(shí)體廣播一條消息,其他實(shí)體偵聽(tīng)該消息。
事件驅(qū)動(dòng)是怎樣用在瀏覽器中的JavaScript的?
借助引擎,JavaScript可以運(yùn)行在你的瀏覽器中。
最受歡迎的 JavaScript 引擎是 Google Chrome 和 Node.js所使用的V8,F(xiàn)irefox 的 SpiderMonkey 和 Safari/WebKit 使用的 JavaScriptCore。
基于供豐富的環(huán)境,JavaScript 引擎增強(qiáng)了語(yǔ)言,還提供了事件驅(qū)動(dòng)的 JavaScript 平臺(tái)。
實(shí)際上,瀏覽器中的 JavaScript 可以與html元素進(jìn)行交互,這些html元素是事件發(fā)送器(event emitters),即能夠發(fā)送事件的對(duì)象。
思考一下這個(gè)簡(jiǎn)單的例子,一個(gè)帶有按鈕的 HTML 文檔:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>What means "event-driven" in JavaScript?</title> </head> <body> <div> <button id="subscribe">SUBSCRIBE</button> </div> </body> </html>
如果沒(méi)有 JavaScript,則這個(gè)按鈕將毫無(wú)生命?,F(xiàn)在 HTML 按鈕是HTMLButtonElement類(lèi)型的元素,并且與所有 HTML 元素一樣,它們都連接到EventTarget—— 每個(gè) HTML 元素的共同祖先。
瀏覽器中的事件目標(biāo)是能夠發(fā)出事件的對(duì)象:它們是觀察者模式中的主題。
有點(diǎn)混亂?請(qǐng)記住:主題是 FM 廣播,所以任何 HTML 元素都像是廣電臺(tái)。
一會(huì)兒,你將看到誰(shuí)是觀察者。
瀏覽器中的主題和觀察者
如果 HTML 元素是主題,那么誰(shuí)是觀察者?任何注冊(cè)為偵聽(tīng)器的 JavaScript函數(shù)都可以對(duì)瀏覽器中的事件做出反應(yīng)。
使用 JavaScript 選擇一個(gè) HTML 元素:
const btn = document.getElementById('subscribe');
并使用 addEventListener注冊(cè)偵聽(tīng)器:
const btn = document.getElementById('subscribe'); btn.addEventListener("click", function () { console.log("Button clicked"); });
這里的“click”是事件,按鈕是主題,或者是發(fā)送器,函數(shù)是偵聽(tīng)器,或者是觀察者。
回顧一下:
HTML 元素是事件發(fā)送器。
JavaScript 中注冊(cè)為偵聽(tīng)器的函數(shù)是觀察者。
所有這些組件構(gòu)成了“一個(gè)小小的事件驅(qū)動(dòng)的體系結(jié)構(gòu)。要測(cè)試代碼請(qǐng)保存下面的 HTML 內(nèi)容到文件(或在 Codepen 上嘗試),請(qǐng)單擊按鈕,然后查看瀏覽器的控制臺(tái):
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>What means "event-driven" in JavaScript?</title> </head> <body> <div> <button id="subscribe">SUBSCRIBE</button> </div> </body> <script> const btn = document.getElementById('subscribe'); btn.addEventListener("click", function () { console.log("Button clicked"); }); </script> </html>
在下一部分中,你將看到用于 Node.js的相同概念。
事件驅(qū)動(dòng)如何用于 Node.js?
Node.js是用于基于 V8 引擎的運(yùn)行在瀏覽器之外(命令行工具和服務(wù)器端)的 JavaScript 環(huán)境。
你在 Node.js 中所做的大部分工作都是基于事件的??倳?huì)有一個(gè)發(fā)送器對(duì)象,一些觀察者在監(jiān)聽(tīng)消息。
在 Node.js 中,沒(méi)有任何 HTML 元素,因此大多數(shù)事件都來(lái)自進(jìn)程、與網(wǎng)絡(luò)的交互、文件等。
Node.js 中的每個(gè)事件發(fā)送器都有一個(gè)名為on的方法,該方法至少需要兩個(gè)參數(shù):
- 要偵聽(tīng)的事件的名稱(chēng)
- 監(jiān)聽(tīng)器函數(shù)
讓我們舉一個(gè)實(shí)際的例子??匆幌逻@個(gè)簡(jiǎn)單的 Node.js 服務(wù)器:
const net = require("net"); const server = net.createServer().listen(8081, "127.0.0.1"); server.on("listening", function () { console.log("Server listening!"); }); server.on("connection", function (socket) { console.log("Client connected!"); socket.end("Hello client!"); });
這段代碼創(chuàng)建了一個(gè)監(jiān)聽(tīng)本地主機(jī)端口 8081 的服務(wù)器。在server 對(duì)象上,我們調(diào)用 on 方法來(lái)注冊(cè)兩個(gè)偵聽(tīng)器函數(shù)。
服務(wù)器啟動(dòng)后立即觸發(fā)listening事件,而客戶(hù)端連接到 127.0.0.1:8081 時(shí)將觸發(fā)connection 事件(嘗試一下!)。
在此示例中,server是事件發(fā)送器,主題。另一方面,偵聽(tīng)器函數(shù)是觀察者。
但是那些on方法從哪里來(lái)的呢?
了解 EventEmitter
Node.js 中的所有事件驅(qū)動(dòng)模塊都擴(kuò)展了一個(gè)名為EventEmitter的根類(lèi)。在我們之前的例子中,來(lái)自 net 模塊的網(wǎng)絡(luò)服務(wù)器就使用了 EventEmitter。
Node.js 中的EventEmitter有兩種基本方法:on和emit。
如果你想要與瀏覽器對(duì)應(yīng),那么可以把EventEmitter看作是能夠發(fā)出事件的任何一種 HTML 元素。
要在瀏覽器中偵聽(tīng)事件,請(qǐng)?jiān)谥黝}對(duì)象上調(diào)用addEventListener:
const btn = document.getElementById('subscribe'); btn.addEventListener("click", function () { console.log("Button clicked"); });
相反,在 Node.js 中有on:
// omit server.on("listening", () => { console.log("Server listening!"); }); // omit
準(zhǔn)確地說(shuō),Eve??ntEmitter上還有一個(gè)addListener方法。on是它的別名。
EventEmitter還有一個(gè)emit方法,在你廣播自定義事件(消息)時(shí)很有用。
如果要使用EventEmitter,請(qǐng)從 “events” 模塊中導(dǎo)入并發(fā)出事件:
const EventEmitter = require("events"); const emitter = new EventEmitter(); emitter.on("customEvent", () => console.log("Got event!")); emitter.emit("customEvent");
用 Node.js 運(yùn)行代碼,你將在控制臺(tái)中看到 “Got event”。
JavaScript 中有關(guān)觀察者/發(fā)布-訂閱的其他示例
JavaScript 沒(méi)有對(duì)觀察者對(duì)象的原生支持,但是有人建議將其添加到語(yǔ)言中。
RxJS是一個(gè)將觀察者模式引入 JavaScript 的庫(kù)。
Redux是 JavaScript 中發(fā)布-訂閱模式的實(shí)現(xiàn)。 這是一個(gè)非常好的事件發(fā)送器,其中狀態(tài)的更改會(huì)被分發(fā)給所有監(jiān)聽(tīng)的觀察者。
現(xiàn)代瀏覽器附帶Intersection Observer API,這是觀察者模式的另一個(gè)例子。
Socket.IO是一個(gè)庫(kù),大量使用了事件。
總結(jié)
希望你從這篇文章中學(xué)到新的東西。你學(xué)到了很多術(shù)語(yǔ),但最終都?xì)w結(jié)為大約 30 年前發(fā)明的模式:發(fā)布-訂閱。
這種模式,也稱(chēng)為觀察者,是我們今天在 JavaScript 和 Node.js 中所使用的事件驅(qū)動(dòng)架構(gòu)的基礎(chǔ)。
再次強(qiáng)調(diào),事件驅(qū)動(dòng)、發(fā)布-訂閱和觀察者的模式并非完全相同:事件驅(qū)動(dòng)的體系結(jié)構(gòu)建立在發(fā)布-訂閱之上,觀察者模式比 DOM 和 Node.js 事件更豐富。
但他們都是屬于同一個(gè)家庭的成員。
以上就是淺談JS和Nodejs中的事件驅(qū)動(dòng)的詳細(xì)內(nèi)容,更多關(guān)于JS和Nodejs中的事件驅(qū)動(dòng)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
javascript實(shí)現(xiàn)頁(yè)面刷新時(shí)自動(dòng)清空表單并選中的方法
這篇文章主要介紹了javascript實(shí)現(xiàn)頁(yè)面刷新時(shí)自動(dòng)清空表單并選中的方法,涉及javascript中reset與focus方法的相關(guān)使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-07-07微信小程序云開(kāi)發(fā)實(shí)現(xiàn)云數(shù)據(jù)庫(kù)讀寫(xiě)權(quán)限
這篇文章主要為大家詳細(xì)介紹了微信小程序云開(kāi)發(fā)實(shí)現(xiàn)云數(shù)據(jù)庫(kù)讀寫(xiě)權(quán)限,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-05-05JS實(shí)現(xiàn)的另類(lèi)手風(fēng)琴效果網(wǎng)頁(yè)內(nèi)容切換代碼
這篇文章主要介紹了JS實(shí)現(xiàn)的另類(lèi)手風(fēng)琴效果網(wǎng)頁(yè)內(nèi)容切換代碼,通過(guò)JavaScript響應(yīng)鼠標(biāo)事件動(dòng)態(tài)操作頁(yè)面元素樣式屬性實(shí)現(xiàn)手風(fēng)琴效果,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-09-09Javascript?promise.all的用法介紹(簡(jiǎn)潔易懂)
這篇文章主要給大家介紹了關(guān)于Javascript?promise.all用法的相關(guān)資料,Promise.all()方法是一個(gè)Promise對(duì)象方法,可以將多個(gè)Promise實(shí)例包裝成一個(gè)新的Promise對(duì)象,最終返回一個(gè)數(shù)組,需要的朋友可以參考下2023-07-072014最熱門(mén)的JavaScript代碼高亮插件推薦
本文給大家推薦今年最流行最熱門(mén)的7款JavaScript代碼高亮插件,各有優(yōu)缺點(diǎn),大家根據(jù)下面的介紹,選擇最適合自己的一款吧。2014-11-11js求數(shù)組最大值的八種具體實(shí)現(xiàn)方法
數(shù)組如何求最大值,想必很多的朋友都不會(huì)吧,下面這篇文章主要給大家介紹了關(guān)于使用js求數(shù)組最大值的八種方法具體實(shí)現(xiàn)的相關(guān)資料,文中給出了詳細(xì)的代碼示例,需要的朋友可以參考下2023-09-09CSS+Table圖文混排中實(shí)現(xiàn)文本自適應(yīng)圖片寬度(超簡(jiǎn)單+跨所有瀏覽器)
最近在為學(xué)樂(lè)網(wǎng)開(kāi)發(fā)圖片顯示功能時(shí)遇到一個(gè)問(wèn)題:在一個(gè)table中有兩行,上邊顯示圖片(大小隨機(jī)),下邊顯示對(duì)圖片的相關(guān)說(shuō)明(文字長(zhǎng)度隨機(jī))2009-02-02使用apply方法處理數(shù)組的三個(gè)技巧[譯]
本文要講的是使用apply方法處理數(shù)組的三個(gè)技巧,需要的朋友可以參考下2012-09-09