做者:孫輝,美團金融前端團隊成員。15年畢業加入美團,相信技術,更相信技術只是大千世界裏知識的一種,我的博客: sunyuhui.comhtml
JavaScript中的事件循環一直都是一個不少人都或多或少了解,但說不清楚的知識點,停留在只知其一;不知其二的層面。之前只須要使用回調函數、定時器還好說,可是自從有了Promise
以後,對事件循環的透徹瞭解就比較重要了。前端
本篇文章不打算從頭開始敘述,那樣篇幅太長,略過最基本的概念,咱們簡單粗暴的把事件循環說清楚。promise
一張圖展現JavaScript中的事件循環:bash
一次事件循環:先運行macroTask
隊列中的一個,而後運行microTask
隊列中的全部任務。接着開始下一次循環(只是針對macroTask和microTask,一次完整的事件循環會比這個複雜的多)。異步
其中macroTask
和microTask
是兩種任務隊列,相比而言,你們更熟悉的一個詞是任務隊列(task queue
,其實就是macroTask
),你們更熟悉的關於事件循環的機制說法大概是:主進程執行完了以後,每次從任務隊列裏取一個任務執行。可是promise
出現以後,這個說法就不太準確了。函數
JavaScript引擎對這兩種隊列有不一樣的處理,簡單的說就是引擎會把咱們的全部任務分門別類,一部分歸爲macroTask
,另一部分歸爲microTask
,下面是類別劃分:oop
咱們所熟悉的定時器就屬於macroTask
,可是僅僅瞭解macroTask
的機制仍是不夠的。學習
上面這些都是理論啊,咱們怎麼直觀的感覺兩種隊列的區別呢?說的再多也不如來一段實踐,咱們感知這種區別最好的方式就是經過任務的執行順序。ui
咱們以setTimeout
、process.nextTick
、promise
爲例直觀感覺下兩種任務隊列的運行方式。spa
console.log('main1');
process.nextTick(function() {
console.log('process.nextTick1');
});
setTimeout(function() {
console.log('setTimeout');
process.nextTick(function() {
console.log('process.nextTick2');
});
}, 0);
new Promise(function(resolve, reject) {
console.log('promise');
resolve();
}).then(function() {
console.log('promise then');
});
console.log('main2');複製代碼
彆着急看答案,先以上面的理論本身想一想,運行結果會是啥?
來個圖片佔個位
最終結果是這樣的:
main1
promise
main2
process.nextTick1
promise then
setTimeout
process.nextTick2複製代碼
process.nextTick
和 promise then
在 setTimeout
前面輸出,已經證實了macroTask
和microTask
的執行順序。可是有一點必需要指出的是。上面的圖容易給人一個錯覺,就是主進程的代碼執行以後,會先調用macroTask
,再調用microTask
,這樣在第一個循環裏必定是macroTask
在前,microTask
在後。
可是最終的實踐證實:在第一個循環裏,process.nextTick1
和promise then
這兩個microTask
是在setTimeout
這個macroTask
裏以前輸出的,這是爲何呢?
由於主進程
的代碼也屬於macroTask
(這一點我比較疑惑的是主進程都是一些同步代碼,而macroTask和microTask包含的都是一些異步任務,爲啥主進程的代碼會被劃分爲macroTask,不過從實踐來看確實是這樣,並且也有理論支撐:【翻譯】Promises/A+規範)。
主進程這個macroTask
(也就是main1
、promise
和main2
)執行完了,天然會去執行process.nextTick1
和promise then
這兩個microTask
。這是第一個循環。以後的setTimeout
和process.nextTick2
屬於第二個循環
別看上面那段代碼好像特別繞,把原理弄清楚了,都同樣 ~
requestAnimationFrame、Object.observe(已廢棄) 和 MutationObserver這三個任務的運行機制你們能夠從上面看到,不一樣的只是具體用法不一樣。重點說下UI rendering
。在HTML規範:event-loop-processing-model裏敘述了一次事件循環的處理過程,在處理了macroTask
和microTask
以後,會進行一次Update the rendering,其中細節比較多,總的來講會進行一次UI的從新渲染。
不知道你們有沒有發現一個現象,在學習技術點的時候,若是太淺,得來的知識點可能不完整甚至是錯的,若是追究的太深,又會給人一種太偏學究的感受,其中的平衡點,你們本身留心把握。
done
另外,你們端午快樂 ~
最後,團隊爲了招聘方便,整了個公衆號,主要是一些招聘信息,團隊信息,全部的技術文章在公衆號裏也能夠看到,對了,若是你想去美團其餘團隊,咱們也能夠幫你內推哦 ~
參考: