JS代碼執(zhí)行過程

一 概念解析:

1 JS編譯

JS不是提前編譯的,而是在執(zhí)行前由JS引擎在幾微秒內(nèi)進行編譯
編譯三部:
1浮庐、詞法分析 (分析有啥詞并整理成詞法單元流(由詞構(gòu)成的數(shù)組))
2、語法分析(詞法單元流整理成抽象語法樹(abstract syntax code,AST))
3会傲、代碼生成(樹整理成機器指令磅废,等待執(zhí)行)
JS在整個編譯過程中的語法分析和代碼生成階段有特定步驟對運行性能進行優(yōu)化缕探。如:對冗余元素優(yōu)化等。
這就是JS被稱之為動態(tài)語言的原因

2 作用域

變量生效的范圍被稱為作用域还蹲。
作用域有兩種主要的工作模型:
1爹耗、詞法作用域耙考,在編譯過程的語法分析階段確定作用域,定義在詞法階段的作用域潭兽,詞法作用域是由變量倦始、塊或函數(shù)作用域定義位置來決定的。
2山卦、動態(tài)作用域鞋邑,在執(zhí)行過程中確定作用域,例如eval可以接受字符串用來欺騙原有作用域账蓉,導(dǎo)致JS引擎在編譯階段的性能優(yōu)化動作失效枚碗,并且難以維護。
js中有三種類型作用域:
a.全局作用域(全局變量擁有全局作用域铸本,在JS代碼中的任何地方都是有定義的)
b.函數(shù)作用域
c.塊級作用域(let const tryCatch with eval可以生成塊級作用域)
同一作用域內(nèi)的所有對象以及變量可以被作用域 內(nèi)的代碼訪問肮雨。

2.1 作用域的由來

ES5 只有全局作用域和函數(shù)作用域,沒有塊級作用域箱玷。
ES6 明確規(guī)定怨规,如果區(qū)塊中存在let和const命令,這個區(qū)塊對這些命令聲明的變量锡足,從一開始就形成了封閉作用域波丰。凡是在聲明之前就使用這些變量,就會報錯舶得。
let和const實際上為 JavaScript 新增了塊級作用域掰烟。
ES5 規(guī)定,函數(shù)只能在頂層作用域和函數(shù)作用域之中聲明沐批,不能在塊級作用域聲明媚赖。

// 情況一
if (true) {
  function f() {}
}

// 情況二
try {
  function f() {}
} catch(e) {
  // ...
}

但是,瀏覽器沒有遵守這個規(guī)定珠插,為了兼容以前的舊代碼惧磺,還是支持在塊級作用域之中聲明函數(shù),因此上面兩種情況實際都能運行捻撑,不會報錯磨隘。
ES6 引入了塊級作用域,明確允許在塊級作用域之中聲明函數(shù)顾患。ES6 規(guī)定番捂,塊級作用域之中,函數(shù)聲明語句的行為類似于let江解,在塊級作用域之外不可引用设预。

// 瀏覽器的 ES6 環(huán)境
function f() { console.log('I am outside!'); }

(function () {
  if (false) {
    // 重復(fù)聲明一次函數(shù)f
    function f() { console.log('I am inside!'); }
  }

  f();
}());
// Uncaught TypeError: f is not a function

如果改變了塊級作用域內(nèi)聲明的函數(shù)的處理規(guī)則,顯然會對老代碼產(chǎn)生很大影響犁河。為了減輕因此產(chǎn)生的不兼容問題鳖枕,ES6 在附錄 B里面規(guī)定魄梯,瀏覽器的實現(xiàn)可以不遵守上面的規(guī)定,有自己的行為方式宾符。

  • 允許在塊級作用域內(nèi)聲明函數(shù)酿秸。
  • 函數(shù)聲明類似于var,即會提升到全局作用域或函數(shù)作用域的頭部魏烫。
  • 同時辣苏,函數(shù)聲明還會提升到所在的塊級作用域的頭部。
    上面的例子實際運行的代碼如下哄褒。
// 瀏覽器的 ES6 環(huán)境
function f() { console.log('I am outside!'); }
(function () {
  var f = undefined;
  if (false) {
    function f() { console.log('I am inside!'); }
  }

  f();
}());
// Uncaught TypeError: f is not a function

引用自: ECMAScript 6 入門

3 作用域鏈

JS中有兩種作用域鏈:
1稀蟋、靜態(tài)作用域鏈:全局、函數(shù)或塊級的作用域鏈(執(zhí)行聲明代碼時創(chuàng)建此作用域鏈)
2呐赡、動態(tài)作用域鏈:執(zhí)行上下文的作用域鏈(在執(zhí)行過程中生成退客,初始化為當(dāng)前作用域的作用域鏈,使用完畢后執(zhí)行上下文被銷毀)

4 執(zhí)行上下文(execution context)罚舱,又叫執(zhí)行環(huán)境:

執(zhí)行上下文是一個JS的內(nèi)部對象遏餐。
擁有作用域的代碼在每次執(zhí)行時都會創(chuàng)建一個獨一無二的執(zhí)行上下文诫隅,代碼執(zhí)行完畢后執(zhí)行上下文被銷毀。
執(zhí)行上下文的生命周期:
1谍咆、創(chuàng)建階段:

ExecutionContext = {  
  ThisBinding = <this value>,     // 確定this 
  LexicalEnvironment = { ... },   // 詞法環(huán)境 存儲函數(shù)聲明和變量( let 和 const )綁定
  VariableEnvironment = { ... },  // 變量環(huán)境 僅用于存儲變量( var )綁定
}

2窃肠、執(zhí)行階段包个,執(zhí)行代碼并賦值
3、執(zhí)行完畢冤留,銷毀執(zhí)行上下文

5 執(zhí)行棧:

執(zhí)行上下文依次放入執(zhí)行棧中碧囊,依次執(zhí)行;單線程的JS纤怒,同一時間只能執(zhí)行一個方法糯而,這些方法被放在一個棧內(nèi)等待執(zhí)行,這個棧就是執(zhí)行棧泊窘。

6 閉包:

閉包是執(zhí)行代碼可以訪問執(zhí)行代碼聲明位置的作用域
1熄驼、函數(shù)在定義時作用域以外的地方被調(diào)用,此函數(shù)在定義時的作用域依然存在且可以被函數(shù)訪問烘豹,這就是閉包瓜贾。(你不知道的JS)
2、閉包類似于JS的內(nèi)置對象携悯,閉包的作用域鏈包含了函數(shù)創(chuàng)建位置的執(zhí)行上下文相同的作用域鏈祭芦,因此在執(zhí)行上下文的作用域在代碼執(zhí)行完畢后無法被銷毀。(高性能JS P25)

在瀏覽器中驗證閉包的描述:

函數(shù)在定義作用域內(nèi)被調(diào)用憔鬼,依然產(chǎn)生了閉包龟劲,只不過這個閉包沒有被保存下來胃夏,執(zhí)行完畢后直接被銷毀。但這不能推翻描述1中的閉包概念咸灿,只能說1中描述的是一個更為嚴格的閉包概念构订,需要函數(shù)在特定位置被調(diào)用才能稱之為閉包(狹義閉包),有實用價值避矢。而閉包的產(chǎn)生更為常見悼瘾,只要函數(shù)調(diào)用自身作用域以外非全局作用域中的值就可以形成閉包(廣義閉包)
瀏覽器中真實觀察到的閉包如下圖审胸。

廣義閉包

經(jīng)典閉包

只包含塊級作用域的閉包

包含塊級作用域和函數(shù)作用域的閉包

二 JS代碼執(zhí)行過程:

1亥宿、引擎編譯JS代碼
2、主線程順序執(zhí)行編譯后的JS代碼
圖中stack是執(zhí)行棧砂沛,heap是存儲基本類型的堆烫扼,圖中少了一個存儲引用類型的棧。
3碍庵、棧內(nèi)執(zhí)行上下文遵循先進后出規(guī)則(FILO)映企。全局執(zhí)行上下文進棧后,直到程序關(guān)閉才會銷毀静浴。
JS主線程在執(zhí)行棧中從上到下執(zhí)行棧內(nèi)代碼堰氓,遇到存在作用域的代碼塊,會向執(zhí)行棧中添加對應(yīng)的執(zhí)行上下文苹享,進入這個執(zhí)行上下文繼續(xù)執(zhí)行代碼双絮,執(zhí)行完畢后會銷毀對應(yīng)的執(zhí)行上下文,直到同步代碼執(zhí)行完畢得问。(執(zhí)行上下文可能存放到了存儲引用類型的棧內(nèi))
4囤攀、當(dāng)遇到異步任務(wù)時,將異步任務(wù)的回調(diào)函數(shù)放入到事件隊列中宫纬,繼續(xù)執(zhí)行代碼焚挠;在此過程中回調(diào)函數(shù)如果引用了函數(shù)外作用域內(nèi)的變量,會將此函數(shù)漓骚,會形成閉包蝌衔。
5、當(dāng)執(zhí)行棧中的代碼執(zhí)行完畢后认境,去事件隊列中檢查是否有可執(zhí)行的回調(diào)函數(shù)胚委,存在,將回調(diào)函數(shù)放入執(zhí)行棧叉信。這個檢查會循環(huán)執(zhí)行亩冬,而這個循環(huán)檢查就是事件循環(huán)

tips:異步任務(wù),例如:定時器硅急、ajax覆享、promise、DOM事件营袜。

JS代碼執(zhí)行過程

執(zhí)行棧遵循FILO

事件隊列遵循FIFO
三 異步任務(wù)的細節(jié):

以上的事件循環(huán)過程是一個宏觀的表述撒顿,不同異步任務(wù)的執(zhí)行優(yōu)先級有區(qū)別。異步任務(wù)被分為兩類:微任務(wù)(micro task)和宏任務(wù)(macro task)荚板。
以下事件屬于微任務(wù):new Promise()凤壁、Object.observe、MurtationObserver
以下事件屬于宏任務(wù):setInterval()跪另、setTimeout()拧抖、dom事件、I/O免绿、UI rendering唧席、requestAnimationFrame

單次事件循環(huán)處理過程中,先處理微任務(wù)嘲驾,所有的微任務(wù)都會被處理淌哟,然后處理宏任務(wù),只處理一個宏任務(wù)辽故。當(dāng)微任務(wù)隊列清空后徒仓,事件循環(huán)會檢查是否需要更新UI視圖。

參考:
這篇參考文章有有些邏輯無法理解
詳解JavaScript中的Event Loop(事件循環(huán))機制
需要參考這篇核對上篇文章
深入理解javascript原型和閉包系列
https://es6.ruanyifeng.com/#docs/let
前端進階系列
形象化解讀js事件循環(huán)以及node事件循環(huán)和瀏覽器事件循環(huán)的區(qū)別
JavaScript事件循環(huán)機制及微任務(wù)與宏任務(wù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末榕暇,一起剝皮案震驚了整個濱河市蓬衡,隨后出現(xiàn)的幾起案子喻杈,更是在濱河造成了極大的恐慌彤枢,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件筒饰,死亡現(xiàn)場離奇詭異缴啡,居然都是意外死亡,警方通過查閱死者的電腦和手機瓷们,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門业栅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人谬晕,你說我怎么就攤上這事碘裕。” “怎么了攒钳?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵帮孔,是天一觀的道長。 經(jīng)常有香客問我,道長文兢,這世上最難降的妖魔是什么晤斩? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮姆坚,結(jié)果婚禮上澳泵,老公的妹妹穿的比我還像新娘。我一直安慰自己兼呵,他們只是感情好兔辅,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著击喂,像睡著了一般幢妄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上茫负,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天蕉鸳,我揣著相機與錄音,去河邊找鬼忍法。 笑死潮尝,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的饿序。 我是一名探鬼主播勉失,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼原探!你這毒婦竟也來了乱凿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤咽弦,失蹤者是張志新(化名)和其女友劉穎徒蟆,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體型型,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡段审,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了闹蒜。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寺枉。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖绷落,靈堂內(nèi)的尸體忽然破棺而出姥闪,到底是詐尸還是另有隱情,我是刑警寧澤砌烁,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布筐喳,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏疏唾。R本人自食惡果不足惜蓄氧,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望槐脏。 院中可真熱鬧喉童,春花似錦、人聲如沸顿天。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽牌废。三九已至咽白,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鸟缕,已是汗流浹背晶框。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留懂从,地道東北人授段。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像番甩,于是被迫代替她去往敵國和親侵贵。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容