javascript是單線程的語言,
能夠單線程將理解爲只有一條車道,在車道里後面的車在等前面的車經過後,才能經過.
即當前面的程序沒有執行,後面的程序也不能執行.javascript
執行棧像"車道",被執行的程序會放入執行棧裏,
但它的執行的順序是,後面進來的程序先執行.前端
視頻源地址vue
在線程中有不少等待運行的任務(程序,而執行棧只會放入一個任務.
其餘可運行任務會放入任務隊列中.
這裏雖然說是個隊列, 它的執行的順序,不會先進的程序先執行.
每一個event loop都會有一個或多個任務隊列java
javascript是單線程,但也能實現異步,這種實現基與頁面提供不少API,如(setTimeout, ajax, addEventListener ...)
這些都是異步函數,也就是說,運行到異步函數時,
把異步函數裏閉包放入web api裏,等待正確的時機,
web api會把閉包放入task queue裏執行.git
macro task有setTimeout ,setInterval, setImmediate,requestAnimationFrame,I/O ,UI渲染...
task queue 是由不少個macro task組成的隊列,github
micro task有Promise, process.nextTick, Object.observe, MutationObserver...
每一個event loop都會有一個micro taskweb
執行流程ajax
<script>// 建立macro task, 由於stack 爲null, 執行 (function test() { setTimeout(() => { // 建立macro task, 當前task queue['第一setTimeout閉包'] console.log(4) }, 0); new Promise(resolve => { console.log(1); // 執行, 控制檯 1 for(var i = 0; i < 10000; i++) { i == 9999 && resolve(); // 建立micro task, 當前micro task queue['第一then閉包'] } console.log(2); // 執行, 控制檯 1 2 }).then(() => { console.log(5); return new Promise(resolve => { resolve() }) }).then(() => { console.log(6) }); console.log(3); /* 執行, 控制檯 1 2 3, 第一個script標籤建立的macro task結束 運行micro task queue首個micro task === 第一then閉包 執行, 控制檯 1 2 3 5, 並建立了micro task 放入 micro task queue['第二then 閉包'] 運行micro task queue首個micro task === 第二then 閉包 執行, 控制檯 1 2 3 5 6 */ })() </script> <script>// 建立macro task, 由於stack 爲null, 執行 (function test2() { setTimeout(function () { // 建立一個macro task 放入 task queue['第一setTimeout閉包' '第二setTimeout閉包'] console.log(42) }, 0); new Promise(function executor (resolve) { console.log(12); // 執行 控制檯1 2 3 5 6 12 for(var i = 0; i < 10000; i++) { i == 9999 && resolve(); // 建立micro task, 當前micro task queue['第一then閉包'] } console.log(22); // 執行 控制檯1 2 3 5 6 12 22 }).then(function() { console.log(52); }); console.log(32); /* 執行, 控制檯 1 2 3 5 6 12 22 32, 第二個script標籤建立的macro task結束 運行micro task queue首個micro task === 第一then閉包 執行, 控制檯 1 2 3 5 6 12 22 32 52, 查看micro task queue首個task爲null, 查看task queue task queue爲空,向web 獲取可執行的任務['第一setTimeout閉包', '第二setTimeout閉包'] 運行task queue首個 macro task === 第一setTimeout閉包 執行, 控制檯 1 2 3 5 6 12 22 32 52 4 查看micro task queue首個task爲null, 查看task queue 運行task queue首個 macro task === 第二setTimeout閉包 執行, 控制檯 1 2 3 5 6 12 22 32 52 4 42 */ })() </script>
在macro/micro task 進入執行棧時,中間應該會有一個緩存區,
例如api
<script> // 建立macro task,進入執行棧 var a = () => { console.log('a'); } var b = () => { console.log('b'); } a(); //這時函數A進入stack,執行,打印出a b(); //這時函數B進入stack,執行,打印出b </script>
若是是把整個macro task放入執行棧,
按後進程序先執行的機制, 應該會先打印'b',
但打印的是'a',說明函數b是等函數a執行完後再進入執行棧的,
因此在macro task 會把裏面的函數拆分爲一個執行的隊列,放入執行棧裏.緩存
https://github.com/ccforward/cc/issues/48
https://juejin.im/entry/596d78ee6fb9a06bb752475c
做者有一年半的前端開發經驗,比較擅長性能優化和vue,喜歡對各類原理的深究,
喜歡籃球和電影
若是有趣味相投能夠加入微信羣