淺薄概念
Javascript是單線程潦俺,執(zhí)行任務(wù)時逾滥,分同步任務(wù)和異步任務(wù),執(zhí)行同步任務(wù)時放入棧中執(zhí)行禁添,執(zhí)行異步任務(wù)時由瀏覽器放入異步隊列撮胧,等同步任務(wù)執(zhí)行完后,再去異步隊列詢問是否有可執(zhí)行的回調(diào)函數(shù)老翘,一直循環(huán)直到異步隊列清空芹啥。
沒有深入!
深入理解
函數(shù)調(diào)用棧和任務(wù)隊列
JavaScript有一個main thread主進程和call-stack(一個調(diào)用堆棧)铺峭,在對
一個調(diào)用堆棧中的task處理的時候墓怀,其他的都要等著。當(dāng)在執(zhí)行過程中遇到一些類似于setTimeout等異步操作的時候卫键,會交給瀏覽器的其他模塊(以webkit為例傀履,是webcore模塊)進行處理,當(dāng)?shù)竭_setTimeout指定的延時執(zhí)行的時間后永罚,task(回調(diào)函數(shù))會放入到任務(wù)隊列直至,一般不同的異步任務(wù)的的回調(diào)函數(shù)會放入不同的任務(wù)隊列之中卧秘。等到調(diào)用棧中所有task執(zhí)行完畢之后呢袱,接著去執(zhí)行任務(wù)隊列中的task(回調(diào)函數(shù))
在上圖中,調(diào)用棧中遇到DOM操作翅敌、ajax請求以及setTimeout等WebAPIs的時候就會交給瀏覽器內(nèi)核的其他模塊進行處理羞福,webkit內(nèi)核在Javasctipt執(zhí)行引擎之外,有一個重要的模塊是webcore模塊蚯涮。對于圖中WebAPIs提到的三種API治专,webcore分別提供了DOM Binding、network遭顶、timer模塊來處理底層實現(xiàn)张峰。等到這些模塊處理完這些操作的時候?qū)⒒卣{(diào)函數(shù)放入任務(wù)隊列中,之后等棧中的task執(zhí)行完之后再去執(zhí)行任務(wù)隊列之中的回調(diào)函數(shù)棒旗。
從setTimeout看事件循環(huán)機制
一個例子來說明事件循環(huán)機制究竟是怎么執(zhí)行setTimeout的喘批。
首先main()函數(shù)的執(zhí)行上下文入棧,
代碼接著執(zhí)行,遇到console.log(‘Hi’),此時log(‘Hi’)入棧铣揉,console.log方法只是一個webkit內(nèi)核支持的普通的方法饶深,所以log(‘Hi’)方法立即被執(zhí)行。此時輸出’Hi’逛拱。
當(dāng)遇到setTimeout的時候敌厘,執(zhí)行引擎將其添加到棧中。
調(diào)用棧發(fā)現(xiàn)setTimeout是之前提到的WebAPIs中的API朽合,因此將其出棧之后將延時執(zhí)行的函數(shù)交給瀏覽器的timer模塊進行處理俱两。
timer模塊去處理延時執(zhí)行的函數(shù)饱狂,此時執(zhí)行引擎接著執(zhí)行將log(‘SJS’)添加到棧中,此時輸出’SJS’锋华。
當(dāng)timer模塊中延時方法規(guī)定的時間到了之后就將其放入到任務(wù)隊列之中嗡官,此時調(diào)用棧中的task已經(jīng)全部執(zhí)行完畢。
調(diào)用棧中的task執(zhí)行完畢之后毯焕,執(zhí)行引擎會接著看執(zhí)行任務(wù)隊列中是否有需要執(zhí)行的回調(diào)函數(shù)衍腥。這里的cb函數(shù)被執(zhí)行引擎添加到調(diào)用棧中,接著執(zhí)行里面的代碼纳猫,輸出’there’婆咸。等到執(zhí)行結(jié)束之后再出棧。
小結(jié)
上面的這一個流程解釋了當(dāng)瀏覽器遇到setTimeout之后究竟是怎么執(zhí)行的芜辕,相類似的還有前面圖中提到的另外的API以及另外一些異步的操作尚骄。
總結(jié)上文說的,主要就是以下幾點:
所有的代碼都要通過函數(shù)調(diào)用棧中調(diào)用執(zhí)行侵续。
當(dāng)遇到前文中提到的APIs的時候倔丈,會交給瀏覽器內(nèi)核的其他模塊進行處理。
任務(wù)隊列中存放的是回調(diào)函數(shù)状蜗。
等到調(diào)用棧中的task執(zhí)行完之后再回去執(zhí)行任務(wù)隊列之中的task需五。
問題
(function test() {
setTimeout(function() {console.log(4)}, 0);
new Promise(function executor(resolve) {
console.log(1);
for( var i=0 ; i<10000 ; i++ ) {
i == 9999 && resolve();
}
console.log(2);
}).then(function() {
console.log(5);
});
console.log(3);
})()
在這段代碼里面,多了一個promise轧坎,那么我們可以思考下面這個問題:
promise的task會放在不同的任務(wù)隊列里面宏邮,那么setTimeout的任務(wù)隊列和promise的任務(wù)隊列的執(zhí)行順序又是怎么的呢?
到這里大家看了我說了這么多的task,那么上文中一直提到的task究竟包括了什么缸血?具體是怎么分的蜜氨?
原文:https://zhuanlan.zhihu.com/p/26229293