在NodeJs和JS中,哪些功能会被放入EventLoop中?

12

为了理解Node.js的异步特性,我读了一些Node.js文章,其中我发现了这篇文章并非常喜欢 Node.js, Doctor’s Offices and Fast Food Restaurants – Understanding Event-driven Programming

有一个叫做EventLoop的东西,它是基于FIFO(先进先出)队列的。当异步函数被触发时,它被放入EventLoop中,然后将在那里继续执行。

我有点困惑。例如在这里就说:

实际上,像setTimeout和setInterval这样的异步函数会被推入称为事件循环的队列中。

同一篇文章中还说:

事件循环是回调函数的队列。当异步函数执行时,回调函数被推入队列中。直到异步函数执行完毕后,JavaScript引擎才开始处理事件循环。

但这与下面的图片不同:

enter image description here

让我们看下面的例子:

console.log("Hello,");
setTimeout(function(){console.log("World");},0);

根据我理解,这些不同的解释得出:

  1. 第一个说,setTimeout()函数中的function(){console.log("World");}部分(回调函数)将被放入事件循环中。一旦setTimeout完成,它也会执行EventLoop
  2. 另一个人说,整个东西setTimeout(function(){console.log("World");},0);将被放入事件循环中并将被执行...

我现在更加困惑了。这应该是一件简单的事情,但我想对以下问题给出一个好但简单的解释:

  1. 前面提到的哪一个说法是正确的?
  2. 什么是事件循环?是一个类比、一个具有方法、对象等的实际事物吗?
  3. 如果我想从头开始实现一个类似于事件循环的东西,它会是什么样子?可以看一下代码。

1
请问这张图片来自哪里? - paulodiovani
4个回答

7

将Node的事件循环视为在客户端上循环的“主函数”(除了Node在服务器端,而且您在代码中不需要技术上的事件循环,因为它是基于事件的:)。

把每个连接的客户端都视为一个JS对象,它在自己的地址空间中运行你的代码,有自己的变量,但在同一个进程和同一个CPU中作为程序的其余部分(你可以对这些进行集群处理,但通常它们默认是这样工作的)。

工作线程是用来分割阻塞I/O的,而使用插件,甚至可以将工作线程分散到不同的Node服务器中(文件I/O、数据库I/O、网络访问等都被放入工作线程中)。

How Node works

当您创建的事件被放入队列中时,执行时会在主事件循环中运行(有点像),但更重要的是,事件本身被放置在事件循环中(将调用它的触发器)。
这都是V8引擎的一部分(即事件循环)。Node之所以如此出色,是因为它允许成千上万的客户端进入同一个循环,并隔离阻塞I/O。
这里的主要观点是:如果需要完成某些任务,Node总是在做某些事情。
而其他框架则会因I/O阻塞代码的执行。

Blocking vs Non-Blocking I/O

基本上,几乎所有你正常编写的东西都将在事件循环中发生,但并非完全如此。意思是你的代码运行一次,然后只插入事件,并退出。

这样讲明白了吗?

所以,当你的代码运行完成时,你排队的任何事件 (包括更多的你的代码,例如)仍然驻留在事件循环中。

Node.js与其他所有东西非常不同,但这是一个相当好的开始解释。

如果您感兴趣,我在Quora上写了更多详细内容... https://www.quora.com/How-good-is-Node-js


6
我将尝试回答,基于MDN关于Event Loops的少量信息。请注意,这个答案仅适用于JavaScript,而不是特定于Node。
听起来,你第二个引用可能应该写得更清晰,例如:
事件循环是一个回调函数队列。当异步函数执行时,回调函数被推入队列中。JavaScript引擎在异步函数后的代码执行之前不会开始处理事件循环。
如果是这样的话,那么它就更加一致了。所有回调函数在触发时都会进入先进先出队列,并按顺序运行。也就是说,如果一个事件正在触发,下一个事件将等待第一个事件完成后才会触发。
我上面链接的MDN参考甚至包括事件循环的伪代码:
while(queue.waitForMessage()){
    queue.processNextMessage();
}

计时器和间隔被定义为HTML规范中DOM的一部分。在我快速检查该规范时,我没有找到任何关于“消息循环”的直接参考。

3
第二个解释是虚假的 - 在 JavaScript 中没有自动将“整个”内容放入事件循环的机制。您的第一种理解是正确的,您可以将事件队列描绘为回调函数数组。事件循环的“迭代”执行队列中的下一个回调并将其删除。回调允许排队更多回调等等。
事件循环还检查外部事件,例如网络活动、用户活动或基于计时器的事件,并为这些操作分派适当的回调。因此,事件循环永远不会退出,除非应用程序关闭。如果当前没有要执行的任务,它只是等待发生事件。

2

基于LIBUV和LIBIO的NodeJS事件循环,请参考此链接https://github.com/joyent/libuv

我对这个不是很清楚,但我知道一点点。

事件循环:

步骤1:我向Nodejs发送一个请求,即从数据库读取文件; 但是数据库已经在使用中(所以将此请求放入事件循环)

步骤2:这时候Nodejs接收到其他请求,比如套接字请求 注意:数据库操作现在很繁忙,而套接字并没有繁忙,因此它执行套接字操作

步骤3:接收多个请求并放置到事件循环中,然后根据I/O执行

I/O: 例如:

   someoFileperation(callback)
    {
          //callback message i am finished any other related process in event loop
           }

   Next process:
    someSocketOperation(calback)
        {
           //Callback message i am finished my socket operation any other related process in Event loop
              }     

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接