我正在考虑,这是我想到的:
让我们在下面看这段代码:
console.clear();
console.log("a");
setTimeout(function(){console.log("b");},1000);
console.log("c");
setTimeout(function(){console.log("d");},0);
一个请求进入,并且JS引擎逐步开始执行上述代码。前两个调用是同步调用。但是当涉及到setTimeout
方法时,它将成为异步执行。但是JS立即从中返回并继续执行,这称为Non-Blocking
或Async
。并且它继续在其他等等上工作。执行结果如下:
因此,基本上第二个
setTimeout
首先完成,并且其回调函数比第一个更早执行,这是有道理的。我们在这里谈论单线程应用程序。 JS Engine会继续执行此操作,除非它完成第一个请求,否则它将不会转到第二个请求。但好处是它不会等待
setTimeout
之类的阻塞操作来解决,因此它会更快,因为它接受新的传入请求。但是我的问题是围绕以下几个方面提出的:
#1:如果我们在谈论单线程应用程序,那么当JS引擎接受更多请求并执行它们时,哪种机制可以处理
setTimeouts
?单线程如何继续处理其他请求?在setTimeout
上起作用的同时其他请求不断进入并被执行的情况。#2:如果这些
setTimeout
函数在有更多请求传入并正在执行时在后台执行,那么在后台执行什么异步执行?我们所说的叫做EventLoop
的东西是什么?#3:但是,是否不应该将整个方法放在
EventLoop
中,以便执行整个操作并调用回调方法?这是我在谈论回调函数时所了解的:function downloadFile(filePath, callback)
{
blah.downloadFile(filePath);
callback();
}
但是在这种情况下,JS引擎如何知道它是否是异步函数,以便可以将回调函数放入EventLoop
中?诸如C#中的async
关键字之类的属性或某种某种属性,它指示JS引擎将采用的方法是异步方法,应进行相应处理。#4:但是article的说法与我猜测事情可能如何运作完全相反:
#5:这里有这张图片可能会有所帮助,但是图片中的第一个解释是说问题4中提到的完全相同的内容:
因此,我的问题是要对上述项目进行一些澄清?
最佳答案
Node 进程中只有1个线程可以实际执行程序的JavaScript。但是,在 Node 本身内部,实际上有多个线程处理事件循环机制的操作,其中包括IO线程池以及其他几个线程。关键是这些线程的数量与在每个连接线程的并发模型中处理的并发连接的数量不同。
现在有关“执行setTimeouts”,当您调用setTimeout
时,所有 Node 所做的基本上就是更新将来一次要执行的函数的数据结构。它基本上有一堆需要做的事情,并且事件循环的每个“滴答声”都选择一个,将其从队列中删除,然后运行它。
需要了解的关键一点是,在大多数繁重的工作中, Node 都依赖于操作系统。因此,传入的网络请求实际上是由OS本身跟踪的,当 Node 准备好处理一个网络请求时,它仅使用系统调用向OS询问网络请求,其中包含准备好处理的数据。 IO的“工作” Node 所做的大部分工作就是“嘿,操作系统,已准备好读取数据的网络连接?”或“嘿,操作系统,我所有未完成的文件系统调用都已准备好数据?”。根据其内部算法和事件循环引擎设计, Node 将选择一个“tick” JavaScript来执行,运行它,然后再次重复该过程。这就是事件循环的含义。基本上, Node 始终在确定“我应该运行的JavaScript的下一部分是什么?”,然后运行它。这会影响操作系统完成的IO以及通过调用setTimeout
或process.nextTick
在JavaScript中排队的内容。
没有JavaScript在后台执行。程序中的所有JavaScript一次都运行在前面和中间。幕后发生的事情是OS处理IO,而 Node 等待IO准备就绪,然后 Node 管理其等待执行的javascript队列。
Node 核心中有一组固定的函数是异步的,因为它们进行系统调用,而 Node 知道这些是因为必须调用OS或C++,所以它们是异步的。基本上,所有网络和文件系统IO以及子进程的交互都是异步的,JavaScript可以使 Node 异步运行某些东西的唯一方法是调用 Node 核心库提供的异步功能之一。即使您使用定义其自己的API的npm包,也要生成事件循环,最终,该npm包的代码将调用 Node 核心的异步函数之一,这是在 Node 知道滴答声已完成并且可以启动事件时再次循环算法。
是的,这是对的,但这是一种误导。关键是正常模式是:
//Let's say this code is running in tick 1
fs.readFile("/home/barney/colors.txt", function (error, data) {
//The code inside this callback function will absolutely NOT run in tick 1
//It will run in some tick >= 2
});
//This code 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的每一个滴答声都必须在合理的时间内产生事件循环,否则整个架构就会失败。