JavaScript的運(yùn)行機(jī)制

執(zhí)行環(huán)境(Execution Context)

JS代碼可以歸為下面三種情況之一:

  • 全局代碼:首先執(zhí)行這里的代碼
  • 函數(shù)代碼
  • Eval代碼:eval()函數(shù)中的文本
20180120_001.jpg

默認(rèn)有一個(gè)全局執(zhí)行環(huán)境,只能有一個(gè)全局執(zhí)行環(huán)境。

執(zhí)行函數(shù)會(huì)創(chuàng)建一個(gè)新的執(zhí)行環(huán)境,可以有多個(gè)函數(shù)執(zhí)行環(huán)境

執(zhí)行環(huán)境棧(Execution Context Stack)

20180120_002.jpg

JS引擎默認(rèn)進(jìn)入全局執(zhí)行環(huán)境執(zhí)行全局代碼,如果在全局代碼中調(diào)用了一個(gè)函數(shù),就會(huì)創(chuàng)建一個(gè)新的執(zhí)行環(huán)境,并添加到棧的頂部,JS引擎始終執(zhí)行棧頂部的執(zhí)行環(huán)境,一旦函數(shù)執(zhí)行完成,當(dāng)前的執(zhí)行環(huán)境就會(huì)被彈出, JS引擎繼續(xù)執(zhí)行下一個(gè)執(zhí)行環(huán)境,直到再次到達(dá)全局執(zhí)行環(huán)境。

執(zhí)行環(huán)境內(nèi)部詳情

調(diào)用執(zhí)行環(huán)境分兩個(gè)階段

1.創(chuàng)建階段

    1. 創(chuàng)建作用域鏈
    1. 創(chuàng)建變量、函數(shù)和參數(shù)
    1. 確定this的值

2.執(zhí)行階段

從上到下逐行執(zhí)行代碼。

從概念上來看,執(zhí)行環(huán)境就像一個(gè)對(duì)象,包含三個(gè)屬性

executionContextObj = {
  // 作用域鏈
  'scopeChain': { /* variableObject + all parent execution context's variableObject */ },

  // 變量對(duì)象
  'variableObject': { /* function arguments / parameters, inner variable and function declarations */ },

  'this': {}
}

執(zhí)行環(huán)境的執(zhí)行流程如下:

  1. 創(chuàng)建執(zhí)行環(huán)境

  2. 進(jìn)入創(chuàng)建階段

  3. 初始化作用域鏈

  4. 創(chuàng)建變量對(duì)象

  5. 創(chuàng)建arguments對(duì)象,arguments對(duì)象創(chuàng)建與參數(shù)名相同的屬性,以引用的方式指向參數(shù)

function a(x, y) {
  console.log(arguments); // { '0': 1, '1': 2 }
  x = 3;
  y = 4;
  console.log(arguments); // { '0': 3, '1': 4 }
}

a(1, 2);
  1. 掃描環(huán)境內(nèi)的函數(shù)聲明

  2. 每發(fā)現(xiàn)一個(gè)函數(shù)聲明,在變量對(duì)象中創(chuàng)建與函數(shù)名相同的屬性,值是指向這個(gè)函數(shù)的指針

  3. 如果這個(gè)函數(shù)名已存在,則重寫這個(gè)指針的值

  4. 掃描環(huán)境內(nèi)的變量聲明

  5. 每發(fā)現(xiàn)一個(gè)變量聲明,在變量對(duì)象中創(chuàng)建與變量名相同的屬性,值初始化為undefined

  6. 如果變量名已存在,則什么也不做

  7. 確定this的值

  8. 進(jìn)入執(zhí)行階段

  9. 逐行執(zhí)行代碼

事件循環(huán)(Event Loop)

JS是單線程,為了不阻塞線程,JS通過事件循環(huán)的方案解決耗時(shí)任務(wù)。

20180120_003.jpg

任務(wù)分兩種:

    1. 宏任務(wù)(Macrotask):script、setTimeout、setInterval、setImmediate、I/O、UI交互事件
    1. 微任務(wù)(Microtask):Promise、process.nextTick、MutaionObserver

對(duì)應(yīng)的任務(wù)隊(duì)列分別是宏任務(wù)隊(duì)列(Macrotask Queue)微任務(wù)隊(duì)列(Microtask Queue)

一開始執(zhí)行的<script>就屬于宏任務(wù)。

Event Loop將一個(gè)宏任務(wù)壓入執(zhí)行環(huán)境棧,在執(zhí)行環(huán)境棧執(zhí)行的過程中,如果遇到任務(wù),則放到相應(yīng)的任務(wù)隊(duì)列中,全部出棧后,清空所有的微任務(wù),依此循環(huán)往復(fù)。

注意,微任務(wù)中會(huì)優(yōu)先清空next tick queue,即通過 process.nextTick 注冊(cè)的函數(shù)。

timer中的0ms和1ms

不管是瀏覽器還是Node,最低延時(shí)是1ms

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

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

打?。? 1

原因如下(Blink源碼和Node源碼):

// https://chromium.googlesource.com/chromium/blink/+/master/Source/core/frame/DOMTimer.cpp#93

double intervalMilliseconds = std::max(oneMillisecond, interval * oneMillisecond);
if (!(after >= 1 && after <= TIMEOUT_MAX))
  after = 1; // schedule on next tick, follows browser behavior

Node中的Event Loop

在 Node 中,如果延時(shí)相同,則會(huì)被合并成一個(gè)任務(wù)

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

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

在 Chrome 打?。? 2 3 4

但在 Node 中打印:1 3 2 4

參考

  1. What is the Execution Context & Stack in JavaScript?
  2. Event Loop的規(guī)范和實(shí)現(xiàn)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 編譯 (解析) 對(duì)于傳統(tǒng)編譯型語言(例如:Java)來說,編譯步驟分為:詞法分析->語法分析->語義檢查->代碼優(yōu)...
    進(jìn)擊的小鐵閱讀 726評(píng)論 2 6
  • 第2章 基本語法 2.1 概述 基本句法和變量 語句 JavaScript程序的執(zhí)行單位為行(line),也就是一...
    悟名先生閱讀 4,560評(píng)論 0 13
  • Node.js是目前非常火熱的技術(shù),但是它的誕生經(jīng)歷卻很奇特。 眾所周知,在Netscape設(shè)計(jì)出JavaScri...
    w_zhuan閱讀 3,732評(píng)論 2 41
  • 一 邊陲客棧當(dāng)壚女 西北邊陲,黃沙滿目。 一家小客棧,在這樣的無邊無際中,蛋黃似的夕陽墜墜,漫天風(fēng)沙卷起時(shí),越發(fā)顯...
    安之若零閱讀 895評(píng)論 15 16
  • 我要說的是關(guān)于眾生的故事,是神圣美好而值得傳頌的故事,是我們這些雙腳行路的人類應(yīng)當(dāng)與四足奔走的動(dòng)物,與展翅翱翔的鳥...
    我的創(chuàng)業(yè)故事采訪閱讀 264評(píng)論 0 6

友情鏈接更多精彩內(nèi)容