JS 和 Node.js 中的“事件驱动”是什么意思?[每日前端夜话0x106]

事件驱动和发布-订阅

事件驱动架构是建立在软件开发中一种通用模式上的,这种模式被称为发布-订阅或观察者模式。

事件驱动架构中,至少有两个参与者:主题(subject)和观察者(observer)。

主题就像调频收音机一样,向有兴趣收听该主题所说内容的观察者进行广播

JS 和 Node.js 中的“事件驱动”是什么意思?[每日前端夜话0x106]

What means "event-driven" in JavaScript and Node.js?
观察者可能只有一个,也可能有一百个,这都没有关系,只要主题有一些要广播的消息就够了。

请记住,事件驱动、发布-订阅和观察者模式在实践中不是一回事,但在理想情况下,它们使用相同的方法:一个实体广播一条消息,其他实体侦听该消息。

发布-订阅模式和我一样老。在 1987 年左右开始理论化,而观察者模式则出现在 1994 年由“四人帮”所写的著作《设计模式》中。

事件驱动是怎样用在浏览器中的 JavaScript 的?

借助引擎,JavaScript 可以运行在你的浏览器中

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

基于供丰富的环境,JavaScript 引擎增强了语言,还提供了事件驱动的 JavaScript 平台。

实际上,浏览器中的 JavaScript 可以与 HTML 元素进行交互,这些 HTML 元素是事件发送器(event emitters),即能够发送事件的对象。

思考一下这个简单的例子,一个带有按钮的 HTML 文档:

1<!DOCTYPE html> 2<html lang="en"> 3<head> 4    <meta charset="UTF-8"> 5    <title>What means "event-driven" in JavaScript?</title> 6</head> 7<body> 8<div> 9    <button id="subscribe">SUBSCRIBE</button>10</div>11</body>12</html>13

如果没有 JavaScript,则这个按钮将毫无生命。现在 HTML 按钮是 HTMLButtonElement 【https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLButtonElement】类型的元素,并且与所有 HTML 元素一样,它们都连接到 EventTarget —— 每个 HTML 元素的共同祖先。

浏览器中的事件目标是能够发出事件的对象:它们是观察者模式中的主题。

有点混乱?请记住:主题是 FM 广播,所以任何 HTML 元素都像是广电台。

一会儿,你将看到谁是观察者

浏览器中的主题和观察者

如果 HTML 元素是主题,那么谁是观察者?任何注册为侦听器的 JavaScript 函数都可以对浏览器中的事件做出反应。

使用 JavaScript 选择一个 HTML 元素:

1const btn = document.getElementById('subscribe');

并使用 addEventListener 注册侦听器:

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

这里的“click”是事件,按钮是主题,或者是发送器,函数是侦听器,或者是观察者。

回顾一下:

HTML 元素是事件发送器

JavaScript 中注册为侦听器的函数是观察者

所有这些组件构成了“一个小小的事件驱动的体系结构。要测试代码请保存下面的 HTML 内容到文件(或在 Codepen 上尝试),请单击按钮,然后查看浏览器的控制台:

1<!DOCTYPE html> 2<html lang="en"> 3<head> 4    <meta charset="UTF-8"> 5    <title>What means "event-driven" in JavaScript?</title> 6</head> 7<body> 8<div> 9    <button id="subscribe">SUBSCRIBE</button>10</div>11</body>12<script>13    const btn = document.getElementById('subscribe');14    btn.addEventListener("click", function () {15        console.log("Button clicked");16    });17</script>18</html>

在下一部分中,你将看到用于 Node.js 的相同概念。

事件驱动如何用于 Node.js?

Node.js 是用于基于 V8 引擎的运行在浏览器之外(命令行工具和服务器端)的 JavaScript 环境。

你在 Node.js 中所做的大部分工作都是基于事件的。总会有一个发送器对象,一些观察者在监听消息。

在 Node.js 中,没有任何 HTML 元素,因此大多数事件都来自进程、与网络的交互、文件等。

Node.js 中的每个事件发送器都有一个名为 on 的方法,该方法至少需要两个参数:

  • 要侦听的事件的名称

  • 监听器函数

让我们举一个实际的例子。看一下这个简单的 Node.js 服务器:

1const net = require("net");2const server = net.createServer().listen(8081, "127.0.0.1");3server.on("listening", function () {4  console.log("Server listening!");5});6server.on("connection", function (socket) {7  console.log("Client connected!");8  socket.end("Hello client!");9});

这段代码创建了一个监听本地主机端口 8081 的服务器。在 server 对象上,我们调用 on 方法来注册两个侦听器函数。

服务器启动后立即触发 listening 事件,而客户端连接到 127.0.0.1:8081 时将触发 connection 事件(尝试一下!)。

在此示例中,server 是事件发送器,主题。另一方面,侦听器函数是观察者

但是那些 on 方法从哪里来的呢?

了解 EventEmitter

Node.js 中的所有事件驱动模块都扩展了一个名为 EventEmitter 的根类。在我们之前的例子中,来自 net 模块的网络服务器就使用了 EventEmitter。

Node.js 中的 EventEmitter 有两种基本方法:on emit

如果你想要与浏览器对应,那么可以把 EventEmitter 看作是能够发出事件的任何一种 HTML 元素。

要在浏览器中侦听事件,请在主题对象上调用 addEventListener:

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

相反,在 Node.js 中有 on:

1// omit2server.on("listening", () => {3  console.log("Server listening!");4});5// omit

准确地说,EventEmitter 上还有一个 addListener 方法。on 是它的别名。

EventEmitter 还有一个 emit 方法,在你广播自定义事件(消息)时很有用。

如果要使用 EventEmitter ,请从 “events” 模块中导入并发出事件:

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

用 Node.js 运行代码,你将在控制台中看到 “Got event”。

JavaScript 中有关观察者/发布-订阅的其他示例

JavaScript 没有对观察者对象的原生支持,但是有人建议将其添加到语言中。

RxJS 是一个将观察者模式引入 JavaScript 的库。【http://reactivex.io/】

Redux 是 JavaScript 中发布-订阅模式的实现。这是一个非常好的事件发送器,其中状态的更改会被分发给所有监听的观察者。,其中状态的更改会被分发给所有监听的观察者。【https://www.valentinog.com/blog/redux/】

现代浏览器附带 Intersection Observer API,这是观察者模式的另一个例子。【https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API】

Socket.IO 是一个库,大量使用了事件。【https://www.valentinog.com/blog/socket-react/#The_WebSocket_protocol_Nodejs_and_SocketIO】

总结

希望你从这篇文章中学到新的东西。你学到了很多术语,但最终都归结为大约 30 年前发明的模式:发布-订阅

这种模式,也称为观察者,是我们今天在 JavaScript 和 Node.js 中所使用的事件驱动架构的基础。

再次强调,事件驱动、发布-订阅和观察者的模式并非完全相同:事件驱动的体系结构建立在发布-订阅之上,观察者模式比 DOM 和 Node.js 事件更丰富。

但他们都是属于同一个家庭的成员。

原文:https://www.valentinog.com/blog/event/

更多相关文章

  1. 观察者模式
  2. Spring 中的事件机制,芳芳用过都说好~
  3. 从事件监听器OnClick中排除按钮
  4. 在不触发hashchange事件的情况下更改哈希
  5. jquery 监控文本框键盘事件(回车事件),附常用keycode值。
  6. 利用jQuery的$.event.fix函数统一浏览器event事件处理
  7. jQuery原生框架-----------------事件
  8. jquery 循环添加事件
  9. iPad上的jQuery点击事件无法正常工作

随机推荐

  1. Android基础笔记(二)-数据存储和界面展现
  2. Android 页面惯性回弹效果,Nested接口接口
  3. Android(安卓)多媒体扫描过程
  4. Android(安卓)HorizontalScrollView嵌套C
  5. android studio 程序员有福了—从layout
  6. Android设计模式-原型模式
  7. android 开发实现静默安装
  8. 数据存储之——Android内、外存储分区&常
  9. Andriod开发必备资料
  10. 关于android WebViewClient的方法解释