Js 運行機制 event loop

Js - 運行機制 (Even Loop)node

Javascript 的單線程 - 引用思否的說法:

JavaScript的一個語言特性(也是這門語言的核心)就是單線程。什麼是單線程呢?簡單地說就是同一時間只能作一件事,當有多個任務時,只能按照一個順序一個完成了再執行下一個。promise

 

那爲何JS是單線程的呢?瀏覽器

  • JS最初被設計用在瀏覽器中,做爲瀏覽器腳本語言,JavaScript的主要用途是與用戶互動,以及操做DOM
  • 若是瀏覽器中的JS是多線程的,會帶來很複雜的同步問題
  • 好比,假定JavaScript同時有兩個線程,一個線程在某個DOM節點上添加內容,另外一個線程刪除了這個節點,這時瀏覽器應該以哪一個線程爲準?
  • 因此爲了不復雜性,JavaScript從誕生起就是單線程

爲了提升CPU的利用率,HTML5提出Web Worker標準,容許JavaScript腳本建立多個線程,可是子線程徹底受主線程控制,且不得操做DOM。因此這個標準並無改變JavaScript單線程的本質;多線程

 

任務隊列 Task queue異步

在Javascript中,全部的任務分爲兩類:同步任務和異步任務函數

同步任務指的是,在主線程上排隊執行的任務,只有前一個任務執行完畢,才能執行後一個任務;oop

異步任務指的是,不進入主線程、而進入"任務隊列"(task queue)的任務,只有"任務隊列"通知主線程,某個異步任務能夠執行了,該任務纔會進入主線程執行。post

簡要說明:在這裏說到了   ‘主線程’   和    ‘任務隊列’ ,我的簡單理解: 主線程就是 Js 執行的線程 , 任務隊列是異步任務暫時存放的一個事件隊列;spa

 

在Js執行中,同步任務和異步任務分別進入不一樣的執行"場所",同步的進入主線程,異步的進入 Event Table 並註冊函數。 線程

當指定的事情完成時,Event Table  會將這個函數移入 Event Queue (事件隊列)。

主線程內的任務執行完畢爲空,會去 Event Queue 讀取對應的函數,進入主線程執行。

上述過程會不斷重複,也就是咱們常說的 Event Loop(事件循環)。

 

經過上邊的描述,咱們來看一張圖更加清晰的瞭解  Event Loop (事件循環) 機制

接下來咱們看一個例子:

        setTimeout(function(){
            console.log('1')
        });
 
        new Promise(function(resolve){
            console.log('2');
            resolve();
        }).then(function(){
            console.log('3')
        });
 
        console.log('4');       

首先setTimeout 是異步進入 事件隊列,而後 promise 的 then 也是異步 進入事件隊列 ,

那麼按照咱們上邊說的Js執行機制,先走主線程的同步任務,打印2 ,而後4,緊跟着執行異步任務,也就是任務隊列打印1,隨後是 3 , 因此結果應該是 2,4,1,3,  事實真的是這樣子嘛 ?  接着往下看 : 

 

Js 中的宏任務和微任務 - 略記一下

macro-task(宏任務) :包括總體代碼  script,setTimeout,setInterval

micro-task(微任務)  : Promise,process.nextTick

process.nextTick(callback)相似node.js版的"setTimeout",在事件循環的下一次循環中調用 callback 回調函數)

 

咱們上邊的  setTimeout  放到了 event queue 事件隊列裏 , promise 的 then 函數 也被放到了 event queue 事件隊列裏,然而杯具來了,這兩個 queue 並非一個隊列;

在 Js  Event Loop 機制中

Promise 執行器中的代碼會被主線程同步調用,可是 promise 的回調函數是基於微任務的

宏任務的優先級高於微任務

每個宏任務執行完畢都必須將當前的微任務隊列清空

emmmm~~

如今咱們回到上邊的例子中,由於 settimeout 是宏任務,雖然先執行的它,可是他被放到了宏任務的 event queue 裏面,而後代碼繼續往下檢查看有沒有微任務,檢測到 Promise 的 then 函數把它放入了微任務隊列。等到主線進程的全部代碼執行結束後。先從微任務

queue 裏拿回調函數,而後微任務queue空了後再從宏任務的queue拿函數。

因此正確的執行結果固然是:2,4,3,1 ;

 

由此延申一下  事循環-宏任務-微任務  (Event Queue - Macro - Micro )關係圖:

 

最後出一個小試題,看看你們是否真的理解到了 Js 的運行機制

試題借鑑  ssssyoki    答案及分析請前往 ssssyoki 博客。

console.log('1');

setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
        console.log('3');
    })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})
process.nextTick(function() {
    console.log('6');
})
new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    console.log('8')
})

setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})
相關文章
相關標籤/搜索