1. 程式人生 > >[轉]JS 引擎的執行機制

[轉]JS 引擎的執行機制

wan queue 多線程 .html 單擊事件 語句 eve resolve title

------------------------------------------------------

JS 引擎的執行機制

關於JS引擎的執行機制,首先牢記2點:

  1. .JS是單線程語言
  2. JS的Event Loop是JS的執行機制。深入了解JS的執行,就等於深入了解JS裏的event loop

關於單線程相對還比較好理解,就是同時只能做一件事,JS最初設計用在瀏覽器中的,如果瀏覽器中的JS是多線程的,那將有可能出現以下場景:

那麽現在有2個進程,process1 process2,由於是多進程的JS,所以他們對同一個dom,同時進行操作。
process1 刪除了該dom,而process2 編輯了該dom,同時下達2個矛盾的命令,瀏覽器究竟該如何執行呢?

這樣想來,JS為什麽是單線程的應該就容易理解了。

那既然JS是單線程了,為了不造成阻塞,對一些比較大的資源,就會采用異步加載的方式,那JS是如何實現異步的呢? 那就是通過事件循環(event loop),理解了event loop機制,就理解了JS的運行機制的難點!

首先看一個栗子,感受一下基本的執行規律:

console.log(1)
setTimeout(function(){
    console.log(2)
},0)
console.log(3);

這個栗子的打印結果為1 3 2

這個地方相對比較好理解,setTimeout裏的函數並沒有立即執行,而是延遲了一段時間,滿足一定條件後才去執行的,這類代碼,我們叫異步代碼。與它相對的console.log()這些就屬於同步任務,按照這種大體的分類方式JS的執行機制是:

  • 首先判斷JS是同步還是異步,同步就進入主進程,異步就進入event table
  • 異步任務在event table中註冊函數,當滿足觸發條件後,被推入event queue
  • 同步任務進入主線程後一直執行,直到主線程空閑時,才會去event queue中查看是否有可執行的異步任務,如果有就推入主進程中

以上三步循環執行,這就是event loop。

所以,上面關於eventloop就是我對JS執行機制的理解,正常情況下,JavaScript的任務是同步執行的,即執行完前一個任務,然後執行後一個任務。只有遇到異步任務的情況下,執行順序才會改變。

這時,需要區分兩種任務:正常任務(task)與微任務(microtask)。它們的區別在於,“正常任務”在下一輪Event Loop執行,“微任務”在本輪Event Loop的所有任務結束後執行

console.log(1);
setTimeout(function() {
  console.log(2);
}, 0);
Promise.resolve().then(function() {
  console.log(3);
}).then(function() {
  console.log(4);
});
console.log(5);
// 打印順序為:1 5 3 4 2

上面代碼的執行結果表明:setTimeout(fn, 0)在Promise.resolve之後執行。

這是因為setTimeout語句指定的是“正常任務”,即不會在當前的Event Loop執行。而Promise會將它的回調函數,在狀態改變後的那一輪Event Loop指定為微任務。所以,3和4輸出在5之後、2之前。

正常任務包括以下情況。

- setTimeout
- setInterval
- setImmediate
- I/O
- 各種事件(比如鼠標單擊事件)的回調函數

微任務目前主要是process.nextTick和 Promise 這兩種情況

所以,判斷JS的任務執行機制的難點就是有多個異步任務,並且是不同類型的異步任務的時候,這個時候先要分清任務是“正常任務”還是“微任務”,“正常任務”要到下一輪Event Loop執行,所以要晚些執行。

參考文章:https://mp.weixin.qq.com/s/WJHD3IFefoVm2MHBgf6oDw
http://javascript.ruanyifeng.com/advanced/timer.html

感謝這些大神的無私分享,以上大部分是他們文章中我個人能夠理解的部分,當然,目前我對Promise的機制的理解還不是特別清楚,下次弄清楚一些了再寫上!

[轉]JS 引擎的執行機制