node js - 回调执行期间传入事件会发生什么

时间:2016-08-31 09:27:59

标签: node.js event-loop

假设我有一些带有大量同步处理的回调。在执行期间,事件循环不能自由轮询传入事件。那么这些事件会发生什么?他们在某个地方排队等待以后处理,还是只是丢失了?

感谢。

3 个答案:

答案 0 :(得分:1)

将它们添加到队列中并稍后处理:

  

JavaScript运行时包含一个消息队列,它是要处理的消息列表。功能与每条消息相关联。当堆栈为空时,将从队列中取出一条消息并进行处理。处理包括调用相关函数(从而创建初始堆栈帧)。当堆栈再次变空时,消息处理结束。

Concurrency model and Event Loop

答案 1 :(得分:1)

他们在从事件队列中被拉出后按顺序排队和处理。

您的JS代码无法阻止新事件进入队列。

答案 2 :(得分:1)

事件循环不会轮询。因此,无法处理事件循环不会影响传入事件。

事件循环如何工作:

大多数现代操作系统(或类似unix的古老操作系统)在操作系统级别而不是应用程序级别处理I / O. POSIX标准要求操作系统至少支持select()系统调用。 select()函数是阻塞函数,大多数程序用它来处理非阻塞I / O.这句话听起来很矛盾,但事实并非如此。

非阻塞I / O如何工作:

我将使用select()作为示例,但不同的操作系统还有其他非阻塞API,如poll()epoll()以及重叠IO(Windows)。各种javascript引擎通常使用类似libuv的库来自动处理在编译时使用的API。

非阻塞API通常提供一个函数,如select(),可阻止和等待应用程序正在侦听的任何I / O上的事件。为什么阻止?因为这是程序使用0%CPU时间的唯一方法。否则,该过程将忙于轮询,这将是非常低效的。

  

旁注:阻塞是什么意思?阻塞基本上是告诉操作系统的任何功能:嘿,我等着这个"事情"所以你可以将我从CPU共享时间表中删除,并且只有在""到达?

非阻塞I / O和阻塞I / O之间的区别不在于您永远不会阻塞,非阻塞I / O块在多个I / O上等待,而阻塞I / O块在单个I / O上等待。如果您想了解更多谷歌select() POSIX功能的文档。

无论如何,javascript使用非阻塞I / O,因此它不会阻止从I / O读取,而是阻塞select()或类似功能。当解释器执行javascript代码时,显然它不会同时调用select()函数。因此,当解释器忙时,操作系统会缓冲发往该程序的任何I / O.

操作系统是否轮询?

没有。操作系统通常不会轮询(然后再次依赖于设备驱动程序,但通常不会)。 I / O活动由中断处理。即使对于非中断驱动的I / O(例如USB),通常处理I / O的芯片组在其缓冲区已满时也会产生中断,因此OS会将数据复制到RAM中的OS缓冲区。有时对于高速设备,它甚至不是执行复制的操作系统,而是DMA控制器,一旦数据被复制到RAM就会产生中断。

GUI活动怎么样?

最后,像鼠标点击和按键操作的GUI活动也是中断驱动的(早期版本的基于DOS的GUI管理器,如Windows 1.0使用轮询驱动的鼠标驱动程序,然后微软看到了Mac OS和传说的演示了它Apple的一名工程师放弃了他们没有进行过调查,因为那时鼠标驱动程序通常会触发中断。)

例外:

一个小的例外是javascript中的线程。我认为是线程中的web worker和node.js中的磁盘I / O处理程序。例如,在node.js中,磁盘I / O驱动程序被实现为在各个线程中阻塞I / O.因此node.js负责在将数据传递回事件循环之前缓冲数据。同样,所有OS缓冲层仍然存在:复制数据(例如OS)可以在node.js线程调用下一个read()之前缓冲已完成的磁盘读取命令。在任何情况下,线程仍然通过I / O通道(管道或套接字或unix域套接字)与事件循环进行通信,因此我上面概述的所有内容仍然成立:如果主js线程忙,则OS将简单地缓冲来自线程的数据(或者如果它被阻塞,那么线程将直接阻塞,直到事件循环处理它们的I / O)。