了解事件循环

Tar*_*rik 126 javascript multithreading asynchronous event-loop node.js

我在想它,这就是我提出的:

假设我们有这样的代码:

console.clear();
console.log("a");
setTimeout(function(){console.log("b");},1000);
console.log("c");
setTimeout(function(){console.log("d");},0);
Run Code Online (Sandbox Code Playgroud)

请求进来,JS引擎开始逐步执​​行上面的代码.前两个呼叫是同步呼叫.但是当谈到setTimeout方法时,它就变成了异步执行.但是JS立即从它返回并继续执行,这被称为Non-BlockingAsync.并继续致力于其他等

执行结果如下:

ACDB

所以基本上第二个setTimeout完成第一个,它的回调函数比第一个更早执行,这是有道理的.

我们在这里谈论单线程应用程序.JS引擎继续执行此操作,除非它完成第一个请求,否则它不会进入第二个请求.但好处是它不会等待阻塞操作,比如setTimeout解决所以它会更快,因为它接受新的传入请求.

但我的问题出现在以下几个方面:

#1:如果我们讨论的是单线程应用程序,那么setTimeouts当JS引擎接受更多请求并执行它们时,什么机制会处理?单个线程如何继续处理其他请求?什么工作,setTimeout而其他请求继续进入并执行.

#2:如果这些setTimeout函数在幕后执行,而有更多请求进入和执行,那么在幕后执行异步执行的是什么?我们谈到的这件事叫EventLoop什么?

#3:但是不应该将整个方法放入,EventLoop以便整个事件被执行并调用回调方法?这是我在谈论回调函数时所理解的:

function downloadFile(filePath, callback)
{
  blah.downloadFile(filePath);
  callback();
}
Run Code Online (Sandbox Code Playgroud)

但在这种情况下,JS引擎如何知道它是否是异步函数,以便它可以将回调EventLoop? Perhaps something like the放在C#中的async`关键字中,或者某种属性指示JS引擎将采用的方法是异步方法并应相应地对待.

#4:但是一篇文章说的与我猜测事情可能如何起作用完全相反:

Event Loop是一个回调函数队列.执行异步函数时,回调函数将被推入队列.在执行异步函数之后的代码之前,JavaScript引擎不会开始处理事件循环.

#5:这里有这个图像可能会有所帮助,但图像中的第一个解释是说第4个问题中提到的完全相同:

在此输入图像描述

所以我的问题是要对上面列出的项目做一些澄清?

Pet*_*ons 82

1:如果我们讨论的是单线程应用程序,那么当JS引擎接受更多请求并执行它们时,什么处理setTimeouts?是不是单个线程会继续处理其他请求?然后谁将继续处理setTimeout,而其他请求继续执行并执行.

节点进程中只有一个线程可以实际执行程序的JavaScript.但是,在节点本身内,实际上有几个线程处理事件循环机制的操作,这包括一个IO线程池和一些其他线程.关键是这些线程的数量与处理的并发连接数不对应,就像在每个连接的并发连接模型中一样.

现在关于"执行setTimeouts",当你调用时setTimeout,所有节点都基本上更新了将来要执行的函数的数据结构.它基本上有一堆需要做的东西和事件循环的每个"滴答",它选择一个,从队列中删除它,然后运行它.

要理解的关键是节点依赖操作系统来完成大部分繁重的工作.因此,传入的网络请求实际上是由操作系统本身跟踪的,当节点准备好处理它时,它只是使用系统调用向操作系统请求数据准备好处理的网络请求.IO"工作"节点的大部分功能都是"Hey OS,网络连接是否已准备好读取数据?" 或者"嘿操作系统,我的任何优秀的文件系统调用都准备好了数据?".基于其内部算法和事件循环引擎设计,节点将选择一个"滴答"的JavaScript来执行,运行它,然后重复该过程.这就是事件循环的含义.Node基本上一直在决定"我应该运行的下一小部分JavaScript是什么?",然后运行它.操作系统已完成IO的因素,以及通过调用setTimeout或在JavaScript中排队的事物process.nextTick.

2:如果这些setTimeout将在幕后执行,而更多请求即将进入和执行,那么事后执行异步执行的事情就是我们正在谈论的事件是EventLoop吗?

没有JavaScript在幕后执行.程序中的所有JavaScript都在前面和中间运行,一次一个.幕后发生的事情是操作系统处理IO和节点等待准备就绪,节点管理其等待执行的javascript队列.

3:JS引擎如何知道它是否是异步函数,以便它可以将它放在EventLoop中?

节点核心中有一组固定的异步函数,因为它们进行系统调用,节点知道这些是因为它们必须调用OS或C++.基本上所有网络和文件系统IO以及子进程交互都是异步的,并且JavaScript可以通过调用节点核心库提供的异步函数之一来让节点异步运行某些东西.即使您使用定义它自己的API的npm包,为了产生事件循环,最终npm包的代码将调用节点核心的异步函数之一,并且当节点知道节拍完成并且它可以启动事件时再次循环算法.

4 Event Loop是一个回调函数队列.执行异步函数时,回调函数将被推入队列.在执行异步函数之后的代码之前,JavaScript引擎不会开始处理事件循环.

是的,这是事实,但这是误导.关键是正常模式是:

//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
Run Code Online (Sandbox Code Playgroud)

所以,是的,你可以完全阻止事件循环,只需在内存中同步计算所有同时的斐波那契数字,是的,这将完全冻结你的程序.这是合作并发.JavaScript的每个滴答必须在一段合理的时间内产生事件循环,否则整个架构将失败.

  • 一般来说它会到达队列的末尾,但是`process.nextTick`对`setTimeout` vs`setImmediate`的语义略有不同,尽管你不应该非常关心.我有一个[博客文章名为setTimeout and friends](http://peterlyons.com/problog/2014/03/settimeout-and-friends),详细介绍. (4认同)

sam*_*rav 59

菲利普罗伯茨有一个很棒的视频教程,它以最简单和概念的方式解释了javascript事件循环.每个javascript开发人员都应该看看.

这是Youtube上的视频链接.

  • 我看了它,这确实是最好的解释. (15认同)

And*_*odi 10

不要认为主机进程是单线程的,它们不是.什么是单线程是执行javascript代码的主机进程的一部分.

除了后台工作者,但这些情况复杂化......

所以,你所有的js代码都在同一个线程中运行,并且你不可能让你的js代码的两个不同部分同时运行(因此,你不会得到并发的nigthmare来管理).

正在执行的js代码是主机进程从事件循环中拾取的最后一个代码.在您的代码中,您基本上可以做两件事:运行同步指令,并安排在将来发生某些事件时要执行的函数.

以下是您的示例代码的心理表示(请注意:我只是,我不知道浏览器实现细节!):

console.clear();                                   //exec sync
console.log("a");                                  //exec sync
setTimeout(                //schedule inAWhile to be executed at now +1 s 
    function inAWhile(){
        console.log("b");
    },1000);    
console.log("c");                                  //exec sync
setTimeout(
    function justNow(){          //schedule justNow to be executed just now
        console.log("d");
},0);       
Run Code Online (Sandbox Code Playgroud)

当您的代码正在运行时,主机进程中的另一个线程会跟踪正在发生的所有系统事件(UI上的点击,读取的文件,收到的网络数据包等)

当代码完成后,它将从事件循环中删除,主机进程将返回检查它,以查看是否有更多代码要运行.事件循环包含两个更多的事件处理程序:一个现在要执行(justNow函数),另一个在一秒内(inAWhile函数).

主机进程现在尝试匹配发生的所有事件,以查看是否有为其注册的处理程序.它发现justNow正在等待的事件已经发生,所以它开始运行它的代码.当justNow函数退出时,它会再次检查事件循环,为事件上的处理程序进行搜索.假设1 s已经过去,它运行inAWhile函数,依此类推......


归档时间:

查看次数:

47287 次

最近记录:

7 年,4 月 前