JS事件循環EventLoop初探

概念

js是基於單線程運行的,而一些特定事件又是異步執行的,因此這種單線程+異步的執行方式必定是事件驅動的 而通常瀏覽器環境下有這樣幾種線程。css

js引擎線程 (解釋執行js代碼、用戶輸入、網絡請求)主線程promise

GUI線程 (繪製用戶界面、與js主線程是互斥的)先繪製dom再繪製css瀏覽器

http網絡請求線程 (處理用戶的get、post等請求,等返回結果後將回調函數推入任務隊列)bash

定時觸發器線程 (setTimeout、setInterval等待時間結束後把執行函數推入任務隊列中)網絡

瀏覽器事件處理線程(將click、mouse等交互事件發生後將這些事件放入事件隊列中)數據結構

上一張經典的eventLoop圖,瞭解幾個基本概念多線程

1,棧(stack):隊列優先,由操做系統自動分配釋放 ,存放函數的參數值,局部變量的值等。其操做方式相似於數據結構中的棧。
2.堆(heap):先進後出;動態分配的空間
JavaScript中的變量分爲基本類型和引用類型。基本類型就是保存在棧內存中的簡單數據段,而引用類型指的是那些保存在堆內存中的對象
這裏引入一個概念(圖上沒有),就是js中的task和microTask 通常來說,咱們把setTimeout,setInterval,瀏覽器的dom操做,用戶點擊等交互事件歸結爲task,而Promise callback Mutation callback還有nextTick咱們歸結爲microTask,

那問題就來了,js中task和microTask執行順序是怎樣的dom

因爲js是單線程,全部的多線程任務最後都要壓入主線程執行棧去執行,如圖所示,task會放入回調隊列裏 由eventLoop取出依次執行。異步

這裏能夠解釋一個小問題,若是多個setTimeout的狀況下,執行時間不是特別的精確,setTimeout 它會在延遲時間結束後分配一個新的 task 至 event loop 中,而不是當即執行,因此 setTimeout 的回調函數會等待前面的 task 都執行結束後再運行。函數

說到這裏好像尚未microTask什麼事,那microTask在何時執行呢,通俗的說,你能夠將microTask理解爲一個愛插隊的大媽,就是在一個task事件結束後,microTask就插入執行棧當即執行,執行順序是主線程執行棧的隊尾插入,callback quene以前

上一段代碼吧,來直觀的瞭解一下執行順序

console.log('start');
  
 setTimeout(function() {
    console.log('setTimeout1');
        setTimeout(function() {
           console.log('setTimeout2');
       },0);
    console.log('setTimeout3');
  }, 0);
  
  Promise.resolve().then(function() {
    console.log('promise1');
  }).then(function() {
   console.log('promise2');
 });
 
 console.log('end');
複製代碼

最後結果是 1,start 2,end 3,promise1 4,promise2 5,setTimeout1,6,setTimeout3 6,setTimeout2

順序是,先執行打印start 而後打印edn 這時候microTask (promise)插隊進入 打印promise1,promise2, 而後執行setTimeout打印setTimeout1,setTimeout3,這裏能夠看作
console.log('setTimeout1');
console.log('setTimeout3');
這兩句一塊兒壓入執行棧,

setTimeout(function() {
        console.log('setTimeout2');
},0);
複製代碼

進入task隊列,由EventLoop取出,因此最後執行順序是 1,start 2,end 3,promise1 4,promise2 5,setTimeout1,6,setTimeout3 6,setTimeout2

相關文章
相關標籤/搜索