Javascript 中的事件循环中有什么内容?

What goes into the event loop in 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'。这样 while 代码块就不会进入事件循环。

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

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

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

这里不是,先打印'first'然后加载setTimeout入栈,但是需要时间,所以移到事件循环中,继续线程,打印'second'.在 500000 毫秒后,它的 setTime 将 return 到调用堆栈,因此是线程。

所以我想知道为什么“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();

1st: 函数 first 添加到 JavaScript 调用堆栈,它输出一个 console.log然后,first 函数从调用堆栈中删除。

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

3rd: 函数 second 添加到 JavaScript 调用堆栈,它输出 console.log然后,从调用堆栈中删除。

4th:当上一个定时器结束时,浏览器将setTimeout的回调函数(不是setTimeout本身)放在事件循环中任务队列,准备好运行.

5th:事件循环查看调用栈,等待调用栈为空。好吧,它是空的,所以事件循环将任务放入调用堆栈并执行。

setTimeout 计时器为零的情况也是如此。

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

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

Note that setTimeout is not a guarantee of time, but of a minimum time.

这是一篇关于事件循环的great lecture