什么会进入Javascript的事件循环?

问题描述

我知道javascript是单线程的,这意味着javascript运行时(浏览器或Node等)会将花费时间的任务发送到事件循环,以便执行平稳运行而不会阻塞它所拥有的线程。但是我对运行时如何决定事件循环的处理方式感到困惑。 (进入事件循环必须执行一些代码块操作)。这可能是由于我缺乏理解,但是无论如何,我将通过一个例子来阐述我的问题。

function first() {
 console.log('first');
}

function second() {
 console.log('second');
}

first()
let i=0;
while(i<1000000000000){
 i++
}
second();

在此senario控制台中,先打印“ first”,然后花费大量时间(可能卡住),再打印“ second”。这样一来,虽然代码块不会进入事件循环。

function first() {
 console.log('first');
}

function second() {
 console.log('second');
}

first()
setTimeout(()=>{},500000);
second();

在这种情况下不是这样,首先,它打印“ first”,然后将setTimeout加载到堆栈,但是这需要时间,因此将其移到事件循环中,继续执行线程,然后打印“ second”。 500000 ms之后,setTime将返回到调用堆栈,从而返回线程。

所以我想知道为什么“ while块”没有进入事件循环,而setTimeout却进入了事件循环。是因为setTimeout是异步调用吗? 但是运行时仍如何知道它是异步的?

解决方法

好的,首先:JavaScript引擎对setTimeout函数一无所知。在较高级别,JavaScript引擎只有一个调用堆栈和一个用于内存管理的堆。 setTimeout不是JavaScript引擎的一部分,它与浏览器的Web API一起提供。 setTimeout永远不会进入调用堆栈,其回调函数会在适当的时间进入。

当您调用setTimeout时,浏览器会为其创建一个计时器并将其放入内存中,当计时器结束时,浏览器将获取其回调函数并将其放入事件循环任务队列中,而不是在JavaScript引擎调用堆栈中。因此,事件循环的实际作用是不断观察JavaScrip调用堆栈,并且当调用堆栈为空时,它将捕获其任务队列中的第一个任务并放入调用堆栈中。

因此,假设您具有以下代码:

function first() {
 console.log('first');
}

function second() {
 console.log('second');
}

first()
setTimeout(()=>{},500000);
second();

第一个:功能第一个已添加到JavaScript调用堆栈中,它输出console.log,然后,第一个功能是从调用堆栈中删除。

第二个::浏览器在其Web API引擎中添加了setTimeout,并为其创建了一个计时器(500秒)。

第3次::功能 second 已添加到JavaScript调用堆栈中,它输出console.log,然后从调用堆栈中删除。

第4个::上一个计时器结束时,浏览器将setTimeout的回调函数(不是setTimeout本身)放入事件循环任务队列中,可以开始运行了

第5个::事件循环查看调用堆栈,并等待直到调用堆栈为空。好的,它是空的,因此事件循环将任务放入调用堆栈并执行。

在setTimeout计时器为零的情况下也会发生同样的情况。

setTimeout(()=> {},0);

如果调用堆栈有很多任务,则setTimeout回调函数可以比其计时器(第二个参数)等待更多的时间

请注意,setTimeout并不是时间的保证,而是最短的时间。

这是关于事件循环的great lecture

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...