一道題引發的EventLoop思考

大明發表於2019-03-03

題目背景

async function async1() {
console.log("async1 start");
await  async2();
 console.log("async1 end");
}
async  function async2() {
 console.log( `async2`);
}
console.log("script start");
setTimeout(function () {
 console.log("settimeout");
},0);
async1();
new Promise(function (resolve) {
 console.log("promise1");
 resolve();
}).then(function () {
 console.log("promise2");
});
console.log(`script end`); 
複製程式碼

題目的本質,是考察setTimeoutpromiseasync await的實現順序及JS的時間迴圈方面的相關問題。

結果為:
script start async1 start async2 promise1 script end async1 end promise2 settimeout

這裡涉及到同步非同步MicrotasksMacrotasksMicrotasks優先順序別高於Macrotasks 其中MicrotasksMacrotasks分別是:

microtasks:

  • process.nextTick
  • promise
  • Object.observe
  • MutationObserver

macrotasks:

  • setTimeout
  • setInterval
  • setImmediate
  • I/O
  • UI渲染
  1. 一個事件迴圈(event loop)會有一個或多個任務佇列(task queue)
  2. task queue 就是 macrotask queue
  3. 每一個 event loop 都有一個 microtask queue
  4. task queue == macrotask queue != microtask queue
  5. 一個任務 task 可以放入 macrotask queue 也可以放入 microtask queue 中

因此事件迴圈的順序,決定了JavaScript程式碼的執行順序。它從script(整體程式碼)開始第一次迴圈。之後全域性上下文進入函式呼叫棧。直到呼叫棧清空(只剩全域性),然後執行所有的micro-task。當所有可執行的micro-task執行完畢之後。迴圈再次從macro-task開始,找到其中一個任務佇列執行完畢,然後再執行所有的micro-task,這樣一直迴圈下去。

定時器是怎麼實現定時的?為什麼會出現不定時的情況?

首先,要明確的一點:javascript是以單執行緒的方式執行的。JavaScript的主要用途是與使用者互動,以及操作DOM。若以多執行緒的方式,則可能出現衝突。假設有兩個執行緒同時操作一個DOM元素,執行緒1要求瀏覽器刪除DOM,而執行緒2卻要求修改DOM樣式,這時瀏覽器就無法決定採用哪個執行緒的操作。當然,我們可以為瀏覽器引入“鎖”的機制來解決這些衝突,但大大提高複雜性,所以 JavaScript從誕生開始就選擇了單執行緒執行。在某一時刻內只能執行特定的一個任務,並且會阻塞其它任務執行。
但是JavaScript 有個基於“Event Loop”併發的模型(不是並行)。前者是邏輯上的同時發生,而後者是物理上的同時發生。所以,單核處理器也能實現併發。
上圖說明一下併發和並行:

佔用

小tips:

console.log(1);
setTimeout(function(){
    console.log(2);
    Promise.resolve(1).then(function(){
        console.log(`ok`)
    })
})
setTimeout(function(){
    console.log(3)
})
複製程式碼

分析:先預設走棧,輸出1。此時並沒有微任務,所以微任務不會執行。先走第一個setTimeout,輸出2,同時將微任務放到佇列中,執行微任務,輸出ok,微任務執行完,再走巨集任務,輸出3。

Node.js的Event Loop

V8引擎解析JavaScript指令碼。
解析後的程式碼,呼叫Node API。
libuv庫負責Node API的執行。它將不同的任務分配給不同的執行緒,形成一個Event Loop(事件迴圈),以非同步的方式將任務的執行結果返回給V8引擎。
V8引擎再將結果返回給使用者。

淺談event loop

相關文章