浏览器中,整个JavaScript的运行环境,在Render进程中。帮助JavaScript运行起来的主要线程包括:
先说明一下浏览器中JavaScript事件循环的整体流程,再来看各个线程在其中起的作用。
浏览器事件循环的总体流程如下:
各组成部分:
整体流程:
setTimeout(()=>console.log("here"),100)
,则调用定时器。setTimeout
定义了100ms的定时,则定时器开始计时,到100ms时,将回调()=>console.log("here")
传递给事件循环队列。如上图所示,JavaScript引擎中主要包括两大部分:
JavaScript是单线程的,而这个单线程,也就是说在JavaScript引擎中,在一个特定时间,JavaScript只能执行一个任务,一行代码,不能同时执行多项任务。代码的执行顺序,则严格按照调用栈的程序调用顺序。
调用栈维护的程序调用及返回顺序,调用栈是一个先进后出的栈结构。
比如以下代码:
function c(){
console.log("c");
}
function b(){
console.log("b");
c();
}
function a(){
console.log("a");
b();
}
a()
代码执行即对应调用栈为:
console.log("a")
。调用栈:main —> a —> console.logconsole.log
执行,打印a
,然后退出console.log
,调用栈变为 main —> ab()
,调用b函数,进入函数b中,调用栈变为 main —> a —> bconsole.log
,调用栈变为 main —> a —> b —> console.logconsole.log
执行完毕,调用栈变为 main —> a —> bconsole.log
,调用栈变为 main —> a —> b —> c —> console.logconsole.log
执行完毕,调用栈变为 main —> a —> b —> cJavaScript引擎会按照代码从上往下进行调用执行
webApis中包含各种浏览器Api调用,比如
setTimeout
或setInterval
,则向定时器注册定时任务,定时器将进行计时,达到执行事件后,将定时器回调传递给事件循环队列事件循环队列每次收到webApi传递来的回调事件及回调数据,则将回调事件及数据放在队列最后,当 JavaScript 调用栈为空时,从循环队列开头,依次将一个个回调事件及数据传递给JavaScript引擎进行执行。
综合上述内容,若代码如下:
console.log("a");
setTimeout(()=>{
console.log("timeout");
},0)
console.log("b");
执行流程为:
console.log
,调用栈变为 main —> console.log ,console.log
执行完毕后,调用栈回到 mainsetTimeout
,调用webapi的定时器,将回调函数传递给定时器,由于设置的超时时间为0,定时器此时会立马把回调传递给时间循环队列,时间循环队列将回调放入队列中console.log("b")
,执行console
,调用栈变为 main —> console,console.log("b")
调用结束,调用栈回到 mainconsole.log("b")
执行完毕后,主代码序列全部执行完毕,调用栈变为空()=>console.log("timeout")
,进行执行,从代码开始执行到执行完毕,调用栈先变为 console.log,后变为空在上面的讲述中,事件循环队列只是一个队列,然而实际上,并不是只有一个队列。然而,事实上应该有两个主要的执行队列。
macrotask
microtask
macrotask、microtask、UI渲染,三者,在某个时刻,只能有一个在执行,它们的执行流程为:
所以,以下代码:
console.log("a");
setTimeout(()=>console.log("b"),0);
Promise.resolve().then(()=>{
console.log("c");
}).then(()=>{
console.log("d");
})
console.log("e");
执行的打印顺序为a - e - c - d - b
参考内容
https://www.youtube.com/watch?v=8aGhZQkoFbQ
https://www.i-programmer.info/programming/javascript/11337-javascript-async-microtasks.html
http://www.dailichun.com/2018/01/21/jssinglethreadeventloop.html