与浏览器 Javascript 的事件侦听器相比,事件包如何在 node.js 中工作

How does events package work in node.js in contrast of event listeners of browser Javascript

我真的很困惑事件和事件处理程序在浏览器中是如何工作的,node.js。

例如,当我们在浏览器中有这样一个脚本时:


const btnEl = ...

btnEl.addEventListener("click" ,() => console.log("handler callback"));

for (let index = 0; index < 100000; index++) {
  console.log(index)
}

我们都知道在for循环中,直到当前匿名函数的当前操作结束,每一次点击事件都不会发生,因为调用栈不为空,事件循环会将点击排队稍后被呼叫的消息。

但是在 node.js 中我看到了不同的行为,比如这个代码:


const EventEmitter = require("events");

const eventEmitter = new EventEmitter();

eventEmitter.on("start", (start, end) => {
  console.log(`started from ${start} to ${end}`);
});

for (let index = 0; index < 20; index++) {
  if (index === 10) {
    eventEmitter.emit("start", 1, 100);
  } else {
    console.log(index);
  }
}

在这段代码中,当我发出事件时,它会打破for循环中的当前循环,然后执行回调,这违反了Javascript引擎的单线程原则。

谁能给我解释一下为什么会这样?

这是第二个代码的输出:

0
1
2
3
4
5
6
7
8
9
started from 1 to 100
11
12
13
14
15
16
17
18
19

你的两个例子完全不同。

eventEmitter.emit("start", 1, 100);在nodejs中是一段同步代码。它根本不经过事件循环。它只是一个函数调用,循环遍历 start 消息的任何侦听器并调用这些侦听器。它只是简单的同步 Javascript。他们称事物为“事件”的事实可能会使事情变得混乱,因为它们与事件循环无关。

另一方面,用户在浏览器中单击会经历事件循环并需要 Javascript 解释器可用,以便它可以获取下一个等待事件,然后调用单击处理程序。

在nodejs中,传入的网络连接或文件读取操作完成等传入事件更类似于浏览器用户点击事件,因为它们会经历事件循环,必须等到当前Javascript 已完成执行,因此可以从事件队列中拉出下一个事件。

仅供参考,如果你想要在 nodejs 中更具可比性,请看这个:

for (let index = 0; index < 20; index++) {
  if (index === 10) {
    setImmediate(() => eventEmitter.emit("start", 1, 100));
  } else {
    console.log(index);
  }
}

然后,您将强制 .emit() 通过事件循环,它将延迟到 for 循环完成后。