Javascript中的事件循环包含什么



我知道javascript是单线程的,这意味着javascript运行时(浏览器或节点等(会将耗时的任务发送到事件循环,这样执行就可以顺利运行,而不会阻塞线程。但我对运行时如何决定事件循环的内容有点困惑。(某个代码块必须做些什么才能进入事件循环(。这可能是因为我缺乏理解,但无论如何,我会举一个例子来阐述我的问题。

function first() {
console.log('first');
}
function second() {
console.log('second');
}
first()
let i=0;
while(i<1000000000000){
i++
}
second();

在这种情况下,控制台打印"第一个",然后花费大量时间(可能卡住(并打印"第二个"。这样while代码块就不会进入事件循环。

function first() {
console.log('first');
}
function second() {
console.log('second');
}
first()
setTimeout(()=>{},500000);
second();

事实并非如此,首先,它打印"First",然后将setTimeout加载到堆栈,但这需要时间,因此将其移动到事件循环中,继续线程,然后打印"second"。500000毫秒后,它的setTime将返回调用堆栈,从而返回线程。

所以我想知道为什么";而块";不会进入事件循环,但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,然后,第一个功能被从调用堆栈中删除。

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

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

4th:当上一个计时器结束时,浏览器将setTimeout的回调函数(而不是setTimeout本身(放入事件循环任务队列中,即可运行。

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

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

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

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

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

这是一堂关于事件循环的精彩讲座。

最新更新