EventLoop
當js引擎遇到一個異步事件后,其實不會說一直等到異步事件的返回一罩,而是先將異步事件進行掛起。等到異步事件執(zhí)行完畢后,會被加入到事件隊列中捉超。(注意亥至,此時只是異步事件執(zhí)行完成妹笆,其中的回調(diào)函數(shù)并沒有去執(zhí)行麻昼。)當執(zhí)行隊列執(zhí)行完畢,主線程處于閑置狀態(tài)時,會去異步隊列那抽取最先被推入隊列中的異步事件贵白,放入執(zhí)行棧中率拒,執(zhí)行其中的回調(diào)同步代碼。如此反復禁荒,這樣就形成了一個無限的循環(huán)俏橘。這就是這個過程被稱為“事件循環(huán)(Event Loop)”的原因。
微任務與宏任務的區(qū)別
這個就像去銀行辦業(yè)務一樣圈浇,先要取號進行排號寥掐。
因為柜員同時職能處理一個來辦理業(yè)務的客戶,這時每一個來辦理業(yè)務的人就可以認為是銀行柜員的一個宏任務來存在的磷蜀,當柜員處理完當前客戶的問題以后召耘,選擇接待下一位,廣播報號褐隆,也就是下一個宏任務的開始污它。
所以多個宏任務合在一起就可以認為說有一個任務隊列在這,里邊是當前銀行中所有排號的客戶庶弃。
任務隊列中的都是已經(jīng)完成的異步操作衫贬,而不是說注冊一個異步任務就會被放在這個任務隊列中,就像在銀行中排號歇攻,如果叫到你的時候你不在固惯,那么你當前的號牌就作廢了,柜員會選擇直接跳過進行下一個客戶的業(yè)務處理缴守,等你回來以后還需要重新取號
而且一個宏任務在執(zhí)行的過程中葬毫,是可以添加一些微任務的,就像在柜臺辦理業(yè)務屡穗,你前邊的一位老大爺可能在存款贴捡,在存款這個業(yè)務辦理完以后,柜員會問老大爺還有沒有其他需要辦理的業(yè)務村砂,這時老大爺想了一下:“最近P2P爆雷有點兒多烂斋,是不是要選擇穩(wěn)一些的理財呢”,然后告訴柜員說础废,要辦一些理財?shù)臉I(yè)務汛骂,這時候柜員肯定不能告訴老大爺說:“您再上后邊取個號去,重新排隊”色迂。
所以本來快輪到你來辦理業(yè)務香缺,會因為老大爺臨時添加的“理財業(yè)務”而往后推手销。
也許老大爺在辦完理財以后還想再辦一個信用卡歇僧?或者再買點兒紀念幣?
無論是什么需求,只要是柜員能夠幫她辦理的诈悍,都會在處理你的業(yè)務之前來做這些事情祸轮,這些都可以認為是微任務。
這就說明:
在當前的微任務沒有執(zhí)行完成時侥钳,是不會執(zhí)行下一個宏任務的适袜。
setTimeout就是作為宏任務來存在的,而Promise.then則是具有代表性的微任務舷夺,上述代碼的執(zhí)行順序就是按照序號來輸出的苦酱。
所有會進入的異步都是指的事件回調(diào)中的那部分代碼
也就是說new Promise在實例化的過程中所執(zhí)行的代碼都是同步進行的,而then中注冊的回調(diào)才是異步執(zhí)行的给猾。
在同步代碼執(zhí)行完成后才回去檢查是否有異步任務完成疫萤,并執(zhí)行對應的回調(diào),而微任務又會在宏任務之前執(zhí)行敢伸。
本來setTimeout已經(jīng)先設置了定時器扯饶,然后在當前進程中又添加了一些Promise的處理。
所以池颈,即便我們繼續(xù)在Promise中實例化Promise尾序,其輸出依然會早于setTimeout的宏任務
實際情況下很少會有簡單的這么調(diào)用Promise的,一般都會在里邊有其他的異步操作躯砰,比如fetch每币、fs.readFile之類的操作。
而這些其實就相當于注冊了一個宏任務琢歇,而非是微任務脯爪。
Promise的實現(xiàn)可以是微任務,也可以是宏任務矿微,但是普遍的共識表示(至少Chrome是這么做的)痕慢,Promise應該是屬于微任務陣營的