1. 程式人生 > 實用技巧 >JavaScript 和 Node.js 中的“事件驅動”是什麼意思?

JavaScript 和 Node.js 中的“事件驅動”是什麼意思?

事件驅動和釋出-訂閱

事件驅動架構是建立在軟體開發中一種通用模式上的,這種模式被稱為釋出-訂閱觀察者模式。

事件驅動架構中,至少有兩個參與者:主題(subject)觀察者(observer)

主題就像調頻收音機一樣,向有興趣收聽該主題所說內容的觀察者進行廣播

觀察者可能只有一個,也可能有一百個,這都沒有關係,只要主題有一些要廣播的訊息就夠了。

請記住,事件驅動、釋出-訂閱和觀察者模式在實踐中不是一回事,但在理想情況下,它們使用相同的方法:一個實體廣播一條訊息,其他實體偵聽該訊息。

釋出-訂閱模式和我一樣老。在 1987 年左右開始理論化,而觀察者模式則出現在 1994 年由“四人幫”所寫的著作《設計模式》中。

事件驅動是怎樣用在瀏覽器中的JavaScript的?

藉助引擎,JavaScript可以執行在你的瀏覽器中

最受歡迎的 JavaScript 引擎是 Google Chrome 和 Node.js所使用的V8,Firefox 的 SpiderMonkey 和 Safari/WebKit 使用的 JavaScriptCore。

基於供豐富的環境,JavaScript 引擎增強了語言,還提供了事件驅動的 JavaScript 平臺

實際上,瀏覽器中的 JavaScript 可以與html元素進行互動,這些html元素是事件傳送器(event emitters),即能夠傳送事件的物件

思考一下這個簡單的例子,一個帶有按鈕的 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>

如果沒有 JavaScript,則這個按鈕將毫無生命。現在 HTML 按鈕是HTMLButtonElement型別的元素,並且與所有 HTML 元素一樣,它們都連線到EventTarget

—— 每個 HTML 元素的共同祖先。

瀏覽器中的事件目標是能夠發出事件的物件:它們是觀察者模式中的主題

有點混亂?請記住:主題是 FM 廣播,所以任何 HTML 元素都像是廣電臺。

一會兒,你將看到誰是觀察者

瀏覽器中的主題和觀察者

如果 HTML 元素是主題,那麼誰是觀察者?任何註冊為偵聽器的 JavaScript函式都可以對瀏覽器中的事件做出反應。

使用 JavaScript 選擇一個 HTML 元素:

constbtn =document.getElementById('subscribe');

並使用 addEventListener註冊偵聽器

const btn = document.getElementById('subscribe');
btn.addEventListener("click", function () {
    console.log("Button clicked");
});

這裡的“click”是事件,按鈕是主題,或者是傳送器,函式是偵聽器,或者是觀察者

回顧一下:

HTML 元素事件傳送器

JavaScript 中註冊為偵聽器的函式是觀察者

所有這些元件構成了“一個小小的事件驅動的體系結構。要測試程式碼請儲存下面的 HTML 內容到檔案(或在 Codepen 上嘗試),請單擊按鈕,然後檢視瀏覽器的控制檯:

<!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的相同概念。

事件驅動如何用於 Node.js?

Node.js是用於基於 V8 引擎的執行在瀏覽器之外(命令列工具和伺服器端)的 JavaScript 環境。

你在 Node.js 中所做的大部分工作都是基於事件的。總會有一個傳送器物件,一些觀察者在監聽訊息。

在 Node.js 中,沒有任何 HTML 元素,因此大多數事件都來自程序、與網路的互動、檔案等。

Node.js 中的每個事件傳送器都有一個名為on的方法,該方法至少需要兩個引數:

  • 要偵聽的事件的名稱
  • 監聽器函式

讓我們舉一個實際的例子。看一下這個簡單的 Node.js 伺服器:

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!");
});

這段程式碼建立了一個監聽本地主機埠 8081 的伺服器。在server 物件上,我們呼叫 on 方法來註冊兩個偵聽器函式。

伺服器啟動後立即觸發listening事件,而客戶端連線到 127.0.0.1:8081 時將觸發connection 事件(嘗試一下!)。

在此示例中,server是事件傳送器,主題。另一方面,偵聽器函式是觀察者

但是那些on方法從哪裡來的呢?

瞭解 EventEmitter

Node.js 中的所有事件驅動模組都擴充套件了一個名為EventEmitter的根類。在我們之前的例子中,來自 net 模組的網路伺服器就使用了 EventEmitter。

Node.js 中的EventEmitter有兩種基本方法:onemit

如果你想要與瀏覽器對應,那麼可以把EventEmitter看作是能夠發出事件的任何一種 HTML 元素。

要在瀏覽器中偵聽事件,請在主題物件上呼叫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

準確地說,Eve​​ntEmitter上還有一個addListener方法。on是它的別名。

EventEmitter還有一個emit方法,在你廣播自定義事件(訊息)時很有用。

如果要使用EventEmitter,請從 “events” 模組中匯入併發出事件:

const EventEmitter = require("events");
const emitter = new EventEmitter();
emitter.on("customEvent", () => console.log("Got event!"));
emitter.emit("customEvent");

用 Node.js 執行程式碼,你將在控制檯中看到 “Got event”。

廣州VI設計公司https://www.houdianzi.com

JavaScript 中有關觀察者/釋出-訂閱的其他示例

JavaScript 沒有對觀察者物件的原生支援,但是有人建議將其新增到語言中。

RxJS是一個將觀察者模式引入 JavaScript 的庫。

Redux是 JavaScript 中釋出-訂閱模式的實現。 這是一個非常好的事件傳送器,其中狀態的更改會被分發給所有監聽的觀察者。

現代瀏覽器附帶Intersection Observer API,這是觀察者模式的另一個例子。

Socket.IO是一個庫,大量使用了事件

總結

希望你從這篇文章中學到新的東西。你學到了很多術語,但最終都歸結為大約 30 年前發明的模式:釋出-訂閱

這種模式,也稱為觀察者,是我們今天在 JavaScript 和 Node.js 中所使用的事件驅動架構的基礎。

再次強調,事件驅動、釋出-訂閱和觀察者的模式並非完全相同:事件驅動的體系結構建立在釋出-訂閱之上,觀察者模式比 DOM 和 Node.js 事件更豐富。

但他們都是屬於同一個家庭的成員。