摘要:解析與編譯從源程序到可以被計算機(jī)識別的目標(biāo)程序主要包含兩個階段解析生成抽象語法樹編譯執(zhí)行解析以引擎為例,前置的解析被分為兩種類型。解釋器就像口譯員,從源代碼第一行開始進(jìn)行解析編譯執(zhí)行。
解析與編譯
Javascript 從源程序到可以被計算機(jī)識別的目標(biāo)程序主要包含兩個階段:
解析生成抽象語法樹
編譯執(zhí)行
解析以V8引擎為例,前置的解析被分為兩種類型:Pre-Parser、Full-Parser。
Pre-Parser,主要負(fù)責(zé)對整個 Javascript 源代碼進(jìn)行必要的前期檢查,判斷是否存在語法錯誤。只在 Top-level 代碼執(zhí)行前進(jìn)行。
這里是一種比較普遍的流程,在使用某個事物之前,靠譜的做法當(dāng)然是先明確下能不能用。
Full-Parser,做的工作相應(yīng)比較多些,包含:
通過分詞/詞法分析、解析/語法分析生成抽象語法樹(Abstract Syntax Tree,AST)
進(jìn)行作用域分析,為變量分配內(nèi)存,生成可用的上下文作用域。具體包括:
將形參作為 GO/AO 的屬性,賦值為實(shí)參值
將變量作為 GO/AO 的屬性,賦值為 undefind
將函數(shù)作為 GO/AO 的屬性,賦值為其函數(shù)體
創(chuàng)建該函數(shù)的作用域鏈等
GO (Global Object),全局環(huán)境下創(chuàng)建全局對象。
AO (Active Object),函數(shù)執(zhí)行前創(chuàng)建激活對象。
Full-Parser,在Top-level代碼和非Top-level代碼執(zhí)行前都會進(jìn)行。函數(shù)在被調(diào)用執(zhí)行前,經(jīng)過Full-Parser生成抽象語法樹提供給JIT編譯器,生成目標(biāo)語言執(zhí)行。
Top-level 是指源代碼初次加載時需要被首先運(yùn)行到的“頂層”代碼。
V8引擎不一次性完成 Javascript 源代碼對應(yīng)的 AST 信息,而是在知道要執(zhí)行哪段代碼前,將這段代碼完成 AST 的生成。
想要了解 AST 信息,可查看 AST 生成工具。
問題:編譯執(zhí)行:
【1】變量提升的原因是因?yàn)闉榱颂岣邎?zhí)行效率,在代碼執(zhí)行前Full-Parser階段為變量分配資源。
【2】函數(shù)聲明優(yōu)先于變量聲明是因?yàn)樽兞柯暶髦粰z查變量是否存在,而函數(shù)聲明需要更新變量值。
在了解JS的編譯過程前,先明確兩個概念:解釋器、編譯器。
解釋器就像口譯員,從源代碼第一行開始進(jìn)行解析編譯執(zhí)行。
編譯器則是直接將完整的源代碼完全編譯生成目標(biāo)程序,從而快速執(zhí)行。
解釋器與編譯器各有各的優(yōu)勢,解釋器能夠快速啟動與執(zhí)行,瀏覽器能夠快速執(zhí)行JS代碼對Web頁面來說是非常重要的,這也是為什么瀏覽器使用解釋器來解析JS源代碼。
但是,在使用解釋器也存在著一些弊端,比如在處理循環(huán)的時候,解釋器并沒有很好的處理重復(fù)的“翻譯”工作。所以在早期(2008年以前)JS執(zhí)行的速度并不是很快。
然而,編譯器除了編譯時間長一些,可以對代碼有更好的優(yōu)化,從而能夠更快的執(zhí)行代碼。因而,在2008年,多種瀏覽器添加了即時編譯器(JIT, just in time),使得JS的執(zhí)行速度提高了10倍。
那么JIT做了些什么事情呢?
JIT包含兩部分構(gòu)成:
基線編譯器
優(yōu)化編譯器
首先源代碼會經(jīng)過基線編譯器解析編譯生成未優(yōu)化的目標(biāo)代碼。同時JS引擎有稱為監(jiān)視器/分析器的部件,記錄代碼執(zhí)行的次數(shù)和方式。
當(dāng)某段代碼執(zhí)行次數(shù)變多時,如函數(shù)頻繁調(diào)用、循環(huán)代碼塊等,基線編譯器會對這段代碼做一些優(yōu)化。當(dāng)這段代碼執(zhí)行次數(shù)越來越多,監(jiān)視器會將這段代碼交給優(yōu)化編譯器,從而生成更快的版本。
為了生成更快的版本,優(yōu)化編譯器必須做一些假設(shè),并且生成的代碼也是默認(rèn)這些假設(shè)都成立的。但是,如果在代碼執(zhí)行過程中,某個假設(shè)失敗了,瀏覽器將執(zhí)行返回到解釋器或者基線編譯的版本。
這個過程稱為去優(yōu)化,所以循環(huán)中數(shù)據(jù)類型與結(jié)構(gòu)的變化可能會對優(yōu)化編譯過程造成影響。
具體流程如下:
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/102002.html
摘要:在動態(tài)解析階段,和會有不同的表現(xiàn)解析為一個預(yù)編譯語句的參數(shù)標(biāo)記符。其次,在預(yù)編譯之前已經(jīng)被變量替換了,這會存在注入問題。預(yù)編譯語句對象可以重復(fù)利用。默認(rèn)情況下,將對所有的進(jìn)行預(yù)編譯??偨Y(jié)本文主要深入探究了對和的不同處理方式,并了解了預(yù)編譯。 mybatis 中使用 sqlMap 進(jìn)行 sql 查詢時,經(jīng)常需要動態(tài)傳遞參數(shù),例如我們需要根據(jù)用戶的姓名來篩選用戶時,sql 如下: sele...
摘要:啟動性能瓶頸分析與解決方案翻譯自的,從屬于筆者的前端入門與工程實(shí)踐。我們必須要清醒地認(rèn)識到全面評測以挖掘出真正性能瓶頸的重要性。這可能是最佳的方式了,類似于這樣的模式鼓勵基于路由的分組,目前被與廣泛使用。 JavaScript 啟動性能瓶頸分析與解決方案 翻譯自 Addy Osmani 的 JavaScript Start-up Performance,從屬于筆者的Web 前端入門與工...
摘要:前言本文內(nèi)容基本摘抄自深入理解虛擬機(jī),以供復(fù)習(xí)之用,沒有多少參考價值。此區(qū)域是唯一一個在虛擬機(jī)規(guī)范中沒有規(guī)定任何情況的區(qū)域。堆是所有線程共享的內(nèi)存區(qū)域,在虛擬機(jī)啟動時創(chuàng)建。虛擬機(jī)上把方法區(qū)稱為永久代。 前言 本文內(nèi)容基本摘抄自《深入理解Java虛擬機(jī)》,以供復(fù)習(xí)之用,沒有多少參考價值。想要更詳細(xì)了解請參考原書。 第二章 1.運(yùn)行時數(shù)據(jù)區(qū)域 showImg(https://segment...
摘要:高級開發(fā)人員可能會仔細(xì)分析他們的捆綁包,以幫助確定減少不必要依賴。在運(yùn)行過程中,長時間運(yùn)行的可以阻塞主線程導(dǎo)致頁面沒有響應(yīng)。然后當(dāng)最終被取出時,附加事件請注意這有內(nèi)在的花銷。發(fā)送一個最小功能的頁面包含實(shí)行當(dāng)前功能的。保持低這些問題。 原文 當(dāng)我們構(gòu)建的網(wǎng)頁大量依賴于Javascript,我們有些時候需要研究那些不太容易看得見的消耗。在這篇文章中,我將介紹為什么一點(diǎn)規(guī)則可以幫助如果你想讓...
閱讀 3891·2021-10-08 10:05
閱讀 2976·2021-09-27 13:57
閱讀 2700·2019-08-29 11:32
閱讀 1023·2019-08-28 18:18
閱讀 1317·2019-08-28 18:05
閱讀 2002·2019-08-26 13:39
閱讀 880·2019-08-26 11:37
閱讀 2064·2019-08-26 10:37