看過不少setTimeout、Promise執行順序的面試題,一直不明白爲啥都是異步操做,Promise就牛×些呢?直到了解了macrotask和micromask才恍然大悟...web
先來一道面試題助助興:面試
setTimeout(()=>{ console.log('A'); },0); var obj={ func: function () { setTimeout(function () { console.log('B') },0); return new Promise(function (resolve) { console.log('C'); resolve(); }) } }; obj.func().then(function () { console.log('D') }); console.log('E'); // 結果:C、E、D、A、B
咱們都知道JavaScript是一門單線程的語言,這也就意味着 JS 沒法進行多線程編程,可是 JS 當中卻有着無處不在的異步概念 。要徹底理解異步,就須要瞭解 JS 的運行核心——事件隊列(Event Loop)。實際上,JS代碼執行都處於事件循環裏。事件循環發現有異步事件發生,就把這個任務放到事件隊伍中。編程
事件隊列是一個存儲着待執行任務的隊列,直白點說就是:咱們把每一次的異步操做(setTimeout、onclick、oninput事件、Promise...)當作一個異步任務,每進行一次異步操做,就把這個異步任務放入到異步事件的隊列中,直到主線程任務執行完畢,而後開始異步的事件隊列裏的任務按順序執行。多線程
Macrotasks和Microtasksapp
Macrotasks和Microtasks 都屬於上述的異步任務中的一種,他們分別有以下API:異步
macrotasks: setTimeout, setInterval, setImmediate, I/O, UI renderingoop
microtasks: process.nextTick, Promise, MutationObserverpost
異步任務隊列分爲 macrotasks 和 microtasks, 在每一次事件循環中,macrotask只會提取一個執行,而microtask會一直提取,直到microsoft隊列爲空爲止。也就是說若是某個microtask任務被推入到執行中,那麼當主線程任務執行完成後,會循環調用該隊列任務中的下一個任務來執行,直到該任務隊列到最後一個任務爲止(microtasks優於macrotasks執行)。而事件循環每次只會入棧一個macrotask,主線程執行完成該任務後又會檢查microtasks隊列並完成裏面的全部任務後再執行macrotask的任務。ui
弄清楚了這條規則後,再來分析上面的面試題就小菜一碟了。 spa
參考文章: