js運行機制和事件循環

編譯原理

任何 JavaScript 代碼片斷在執行前都要進行編譯(一般就在執行前)。所以,JavaScript編譯器首先會對 var a = 2; 這段程序進行編譯,而後作好執行它的準備,而且一般立刻就會執行它。node

編譯通常分爲三步:編程

  • 分詞/詞法分析(Tokenizing/Lexing)
    這個過程會將由字符組成的字符串分解成(對編程語言來講)有意義的代碼塊,這些代

碼塊被稱爲詞法單元(token)。例如,考慮程序 var a = 2;。這段程序一般會被分解成
爲下面這些詞法單元:var、a、=、2 、;。空格是否會被看成詞法單元,取決於空格在
這門語言中是否具備意義。數組


  • 解析/語法分析(Parsing)

這個過程是將詞法單元流(數組)轉換成一個由元素逐級嵌套所組成的表明了程序語法
結構的樹。這個樹被稱爲「抽象語法樹」 (Abstract Syntax Tree,AST)。
var a = 2; 的抽象語法樹中可能會有一個叫做VariableDeclaration 的頂級節點,接下
來是一個叫做Identifier(它的值是a)的子節點,以及一個叫做AssignmentExpression
的子節點。AssignmentExpression 節點有一個叫做 NumericLiteral(它的值是 2)的子
節點。promise


  • 代碼生成

將 AST 轉換爲可執行代碼的過程被稱爲代碼生成。這個過程與語言、目標平臺等息息
相關。
拋開具體細節,簡單來講就是有某種方法能夠將var a = 2; 的AST轉化爲一組機器指
令,用來建立一個叫做 a 的變量(包括分配內存等),並將一個值儲存在a 中。瀏覽器

單線程

js引擎是單線程的,編譯和執行js的線程只有一個。
nodejs和瀏覽器還有別的線程用於處理其它任務,如處理AJAX請求的線程、處理DOM事件的線程、定時器線程、讀寫文件的線程。異步

單線程因此有了事件循環。async

消息隊列和事件循環

函數調用造成一個棧幀,放入當前執行棧中,幀中包含了當前context須要的參數和局部變量。編程語言

堆棧隊列.png

一個 JavaScript 運行時包含了一個待處理的消息隊列。每個消息都關聯着一個用以處理這個消息的函數。函數

其它線程將消息放到消息隊列,js線程經過事件循環過程去獲取消息。spa

在事件循環期間的某個時刻,運行時從最早進入隊列的消息開始處理隊列中的消息。爲此,這個消息會被移出隊列,並做爲輸入參數調用與之關聯的函數。

函數的處理會一直進行到執行棧再次爲空爲止;而後事件循環將會處理隊列中的下一個消息。

異步中的微任務、宏任務

  • 宏任務(task):script,setTimeout,setInterval、setImmediate
  • 微任務(microtask):原生Promise(有些實現的promise將then方法放到了宏任務中)、process.nextTick、Object.observe(已廢棄)、 MutationObserver

執行邏輯很簡單,就是先清空當前context的micortask,再執行task

一個例子:

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')
    })
})

Promise.resolve().then(r=>console.log(16))

async function a1(){
    console.log('13')
    await console.log('14')
    console.log('15')
}

process.nextTick(function() {
    console.log('6');
})

new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    console.log('8')
})

a1()

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