轉: 原文 http://blog.csdn.net/sjn0503/article/details/76087631javascript
----------------------------------------------------html
放個面試題,拋個磚:前端
console.log('start') const interval = setInterval(() => { console.log('setInterval') }, 0) setTimeout(() => { console.log('setTimeout 1') Promise.resolve() .then(() => { console.log('promise 3') }) .then(() => { console.log('promise 4') }) .then(() => { setTimeout(() => { console.log('setTimeout 2') Promise.resolve() .then(() => { console.log('promise 5') }) .then(() => { console.log('promise 6') }) .then(() => { clearInterval(interval) }) }, 0) }) }, 0) Promise.resolve() .then(() => { console.log('promise 1') }) .then(() => { console.log('promise 2') })
不着急揭曉答案,先分析java
首先知曉:web
js是單線程語言面試
也就是說一次就只能作一件事情。api
多數的網站不須要大量計算,程序花費的時間主要集中在磁盤 I/O 和網絡 I/O 上面promise
雖然SSD讀取很快,但和CPU處理指令的速度比起來也不在一個數量級上,並且網絡上一個數據包來回的時間更慢(注意過遊戲的延遲嗎)網絡
so: 一些cpu直接執行的任務就成了優先執行主線任務,而後須要io返回數據的任務就成了等待被執行的任務app
因此纔會有同步任務(synchronous)和異步任務(asynchronous)之分
同步任務:
在主線程上排隊執行的任務,前一個任務執行完畢,才能執行後一個任務;
異步任務:
不進入主線程、而進入」任務隊列」(task queue)的任務,只有」任務隊列」通知主線程,某個異步任務能夠執行了,該任務纔會進入主線程執行。
總之:
只要主線程空了,就會去讀取」任務隊列」,這就是JavaScript的運行機制
任務隊列不止一個,還有 microtasks 和 macrotasks
microtasks:
macrotasks:
whatwg規範:https://html.spec.whatwg.org/multipage/webappapis.html#task-queue
理解了這些定義以後,再看執行原理:
事件循環的順序,決定了JavaScript代碼的執行順序。它從script(總體代碼)開始第一次循環。以後全局上下文進入函數調用棧。直到調用棧清空(只剩全局),而後執行全部的micro-task。當全部可執行的micro-task執行完畢以後。循環再次從macro-task開始,找到其中一個任務隊列執行完畢,而後再執行全部的micro-task,這樣一直循環下去。
還要注意一點:
包裹在一個 script 標籤中的js代碼也是一個 task 確切說是 macrotask。
因此文首面試題的答案爲:
start
promise 1
promise 2
setInterval
setTimeout 1
promise 3
promise 4
setInterval
setTimeout 2
promise 5
promise 6
簡單來說,總體的js代碼這個macrotask先執行,同步代碼執行完後有microtask執行microtask,沒有microtask執行下一個macrotask,如此往復循環至結束.
--------------------------------------------------------2017年11月14日21:35:17---------------------------------------------------------------
另外,這篇文章也不錯
這個知識點。。。
https://blog.keifergu.me/2017/03/23/difference-between-javascript-macrotask-and-microtask/?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io
這個系統也超屌!!
http://www.jianshu.com/p/cd3fee40ef59
=======================
Macrotask 和 microtask 都是屬於上述的異步任務中的一種,咱們先看一下他們分別是哪些 API :
setTimeout
, setInterval
, setImmediate
, I/O, UI renderingmicrotasks: process.nextTick
, Promises
, Object.observe
(廢棄), MutationObserver
任務隊列分爲 macrotasks 和 microtasks,而Promise
中的then
方法的函數會被推入 microtasks 隊列,而setTimeout
的任務會被推入 macrotasks 隊列。在每一次事件循環中,macrotask 只會提取一個執行,而 microtask 會一直提取,直到 microtasks 隊列清空。
注:通常狀況下,macrotask queues 咱們會直接稱爲 task queues,只有 microtask queues 纔會特別指明。
那麼也就是說若是個人某個 microtask 任務又推入了一個任務進入 microtasks 隊列,那麼在主線程完成該任務以後,仍然會繼續運行 microtasks 任務直到任務隊列耗盡。
而事件循環每次只會入棧一個 macrotask ,主線程執行完該任務後又會先檢查 microtasks 隊列並完成裏面的全部任務後再執行 macrotask。
=======================
測試代碼:
<script> console.log('script start'); setTimeout(function() { console.log('setTimeout'); },0); Promise.resolve().then(function() { console.log('promise'); }).then(function() { console.log('promise2'); }); console.log('script end'); </script>