1:如果我们谈论的是单线程应用程序,那么当JS引擎接受更多请求并执行它们时,什么处理setTimeouts?那不是单线程将继续处理其他请求吗?然后谁将继续处理setTimeout,而其他请求继续出现并被执行。
节点进程中只有1个线程可以实际执行程序的Javascript。但是,在节点本身内部,实际上有多个线程处理事件循环机制的操作,其中包括IO线程池以及其他几个线程。关键是这些线程的数量与在每个连接线程的并发模型中处理的并发连接的数量不同。
现在关于“执行setTimeouts”,当您调用时
setTimeout,所有节点所做的基本上就是更新将来一次执行的函数的数据结构。它基本上有一堆需要做的事情,并且事件循环的每个“滴答声”都选择一个,将其从队列中删除,然后运行它。
需要了解的关键一点是,在大多数繁重的工作中,节点都依赖于操作系统。因此,传入的网络请求实际上是由OS本身跟踪的,当节点准备好处理一个网络请求时,它仅使用系统调用向OS询问网络请求,其中包含准备好处理的数据。IO的“工作”节点所做的大部分工作就是“嘿,操作系统,已准备好读取数据的网络连接?”
或“嘿,操作系统,我所有未完成的文件系统调用都已准备好数据?”。根据其内部算法和事件循环引擎设计,节点将选择一个“ tick”
Javascript来执行,运行它,然后再次重复该过程。这就是事件循环的含义。基本上,节点始终在确定“接下来我应该运行什么Javascript?”,然后运行它。
setTimeout或
process.nextTick。
2:如果这些setTimeout将在更多请求传入和执行期间在后台执行,那么在后台执行异步执行的事情就是我们在谈论EventLoop吗?
没有Javascript在后台执行。程序中的所有Javascript一次都运行在前面和中间。幕后发生的事情是OS处理IO,而节点等待IO准备就绪,然后节点管理等待执行的javascript队列。
3:JS引擎如何知道它是否是异步函数,以便可以将其放入EventLoop中?
节点核心中有一组固定的函数是异步的,因为它们进行系统调用,而节点知道这些是什么,因为它们必须调用OS或C
++。基本上所有网络和文件系统IO以及子进程的交互都是异步的,Javascript可以使节点异步运行某些东西的唯一方法是调用节点核心库提供的异步功能之一。即使您使用定义其自己的API的npm包,也要生成事件循环,最终,该npm包的代码将调用节点核心的异步功能之一,并且在该时刻,节点知道滴答已完成并且可以启动事件再次循环算法。
4事件循环是回调函数的队列。当执行异步函数时,回调函数将被推入队列。在执行异步函数后的代码之前,Javascript引擎不会开始处理事件循环。
是的,这是真的,但这是误导。关键是正常模式是:
//Let's say this pre is running in tick 1fs.readFile("/home/barney/colors.txt", function (error, data) { //The pre inside this callback function will absolutely NOT run in tick 1 //It will run in some tick >= 2});//This pre will absolutely also run in tick 1//HOWEVER, typically there's not much else to do here,//so at some point soon after queueing up some async IO, this tick//will have nothing useful to do so it will just end because the IO result//is necessary before anything useful can be done因此,是的,您可以通过仅在同一滴答声中同步计数所有内存中的斐波那契数来完全阻止事件循环,是的,这将完全冻结您的程序。这是合作并发。Javascript的每一个滴答声都必须在合理的时间内产生事件循环,否则整个架构就会失败。



