js高級之js運行原理

1.瀏覽器渲染過程

1.1 下載文件【掌握】

當(dāng)我們輸入一個網(wǎng)址之后,dns服務(wù)器將網(wǎng)址中的域名解析為ip地址(服務(wù)器地址)之后,(這個過程就是通過網(wǎng)址找服務(wù)器地址)。

找到服務(wù)器地址后,通常會返回一個index.html網(wǎng)頁,然后瀏覽器開始解析html網(wǎng)頁,解析的過程會遇到加載css的標簽-》從服務(wù)器下載css文件,遇到script標簽-》下載對應(yīng)的js文件,js相關(guān)的代碼也會執(zhí)行,比如寫了一個函數(shù),執(zhí)行完后,就能在瀏覽器里運行這個函數(shù)。

1.2 執(zhí)行文件

瀏覽器內(nèi)核(排版引擎)幫助我們解析代碼。

1.2.1.html css解析【掌握】

來看看瀏覽器的渲染過程

圖片.png

1.瀏覽器內(nèi)核幫助解析html文件,通過html parser將html文件轉(zhuǎn)化成dom樹,
在這個過程中可以編寫了js代碼來對dom進行操作,代碼由js引擎執(zhí)行。
2.樣式文件由css parser進行解析生成樣式規(guī)則style rules,然后和dom樹合在一起形成渲染樹
3.通過布局引擎對渲染樹在進行一步操作形成最終的渲染樹
4.最后進行繪制 -> 瀏覽器展示

1.2.2.js代碼執(zhí)行

1.2.2.1.為什么需要js引擎

  • 高級的編程語言都是需要轉(zhuǎn)成最終的機器指令來執(zhí)行的;
  • 事實上我們編寫的JavaScript無論你交給瀏覽器或者Node執(zhí)行,最后都是需要被CPU執(zhí)行的;
  • 但是CPU只認識自己的指令集,實際上是機器語言,才能被CPU所執(zhí)行;
  • 所以我們需要JavaScript引擎幫助我們將JavaScript代碼翻譯成CPU指令來執(zhí)行;

1.2.2.2.瀏覽器內(nèi)核和JS引擎的關(guān)系

瀏覽器內(nèi)核分為兩種:渲染引擎和js引擎。

最開始渲染引擎和js引擎并沒有很嚴格的區(qū)分,后來js引擎越來越獨立,內(nèi)核則傾向于只指渲染引擎,內(nèi)核的種類很多,常見的內(nèi)核有四種:Trident / Gecko / Blink / Webkit

這里我們先以WebKit為例,WebKit事實上由兩部分組成的:

  • WebCore:負責(zé)HTML解析、布局、渲染等等相關(guān)的工作;
  • JavaScriptCore:解析、執(zhí)行JavaScript代碼;
    另外一個強大的JavaScript引擎就是V8引擎。

1.1.2.3.v8引擎的原理【理解】

1.定義

  • V8是用C ++編寫的Google開源高性能JavaScript和WebAssembly引擎,它用于Chrome和Node.js等。

  • 它實現(xiàn)ECMAScript和WebAssembly,可以在很多環(huán)境下運行,比如說:Windows 7或更高版本,macOS 10.12+和使用x64,IA-32, ARM或MIPS處理器的Linux系統(tǒng)上運行。

  • 它也可以獨立運行,也可以嵌入到任何C ++應(yīng)用程序中。(很少)
    2.底層架構(gòu)


    圖片.png
  • 1.編寫了js代碼想要交給cpu去執(zhí)行,但是js代碼直接放在cpu里面,cpu無法識別,cpu只能識別0101這樣的機器語言,所以js代碼需要借助v8引擎。

  • 2.parse對代碼進行語法分析和詞法分析->生成抽象語法樹
    https://astexplorer.net/

  • 3.拿到抽象語法樹,我們可以把它轉(zhuǎn)化成es5的代碼也可以轉(zhuǎn)化成字節(jié)碼,轉(zhuǎn)化成字節(jié)碼需要用的一個庫ignition(轉(zhuǎn)化器)。
    為什么不直接轉(zhuǎn)成0101機器語言?
    因為無法確定這個代碼會運行在怎樣的環(huán)境上(windows,mac,linux),不同環(huán)境的cpu架構(gòu)不同,不同cpu架構(gòu)能執(zhí)行的機器指令不同,所以無法確定機器指令,所以才轉(zhuǎn)化為字節(jié)碼。
    字節(jié)碼可以跨平臺,轉(zhuǎn)化為機器指令后就可以運行了。

  • 4.字節(jié)碼需要轉(zhuǎn)化成匯編指令,再轉(zhuǎn)化為機器指令才可以運行
    這個過程有點耗時,如果代碼(函數(shù))執(zhí)行多次,把這個函數(shù)保存下來,之后就能直接從字節(jié)碼生成機器指令了。

v8引擎有一個庫,TurboFan 。ignition收集函數(shù)執(zhí)行信息,標注執(zhí)行頻率高的函數(shù),通過TurboFan將這些函數(shù)轉(zhuǎn)化為優(yōu)化的機器碼,之后再執(zhí)行的時候就不需要經(jīng)過復(fù)雜的轉(zhuǎn)化過程了,直接執(zhí)行機器指令,得到運行結(jié)果,可以提高性能。

有一個問題,比如說保存了高頻率函數(shù)

function sum(num1,num2){
  return num1+num2
} 
sum(20,20) 
sum(30,30) 
sum('aa','bb').

當(dāng)優(yōu)化的機器碼發(fā)現(xiàn)執(zhí)行指令不同時(數(shù)值相加變成了字符串拼接),會進行一個操作deoptimzation,反優(yōu)化到字節(jié)碼后再轉(zhuǎn)化成運行結(jié)果。
這樣會消耗性能,所以在寫代碼的時候使用typescript,有一個類型的限制,效率會更高一些。

ps:預(yù)解析:解析會執(zhí)行的函數(shù)和變量

2.js代碼執(zhí)行過程【掌握】

var name = "jim"
var num1 = 20
var num2 = 30 
var result = num1 + num2

2.0.選擇代碼運行環(huán)境

瀏覽器(包含v8引擎):在html內(nèi)加載js文件,
node環(huán)境終端(包含v8引擎/其他js引擎):命令行-》node js文件

2.1.初始化全局對象

代碼在運行之前需要被解析。
解析時(js源代碼到ast抽象語法樹的解析過程)

v8引擎會幫我們初始化全局對象GlobalObject-GO,包含環(huán)境(瀏覽器或者node)內(nèi)的全局變量(settimeou函數(shù)t,String類...),Window屬性(指向globalObject)和代碼里面定義的變量(尚未賦值的name,num1...,因為還沒有執(zhí)行所以未賦值)

var globalObject = {
  String: "類",
  Date: "類",
  setTimeount: "函數(shù)",
  window: globalObject,
  name: undefined,
  num1: undefined,
  num2: undefined,
  result: undefined
}

2.2.執(zhí)行上下文棧中運行代碼

為了執(zhí)行代碼, v8引擎內(nèi)部會有一個執(zhí)行上下文棧(Execution Context Stack, ECStack)(函數(shù)調(diào)用棧),(其實就是內(nèi)存,代碼要執(zhí)行的話需要先從磁盤加載到內(nèi)存里面去,在內(nèi)存中將代碼轉(zhuǎn)化成對應(yīng)的機器指令,最后在cpu中進行執(zhí)行。)
ps:對內(nèi)存會劃分結(jié)構(gòu),分別是棧結(jié)構(gòu)和堆結(jié)構(gòu)。

代碼要執(zhí)行都需要放到執(zhí)行上下文棧中,一般是放函數(shù)。

2.3.在執(zhí)行上下文棧中執(zhí)行全局代碼

因為我們執(zhí)行的是全局代碼, 為了全局代碼能夠正常的執(zhí)行, 需要創(chuàng)建 全局執(zhí)行上下文(Global Execution Context)(全局代碼需要被執(zhí)行時才會被創(chuàng)建),然后放進ECStack里。全局執(zhí)行上下文中有一個VO變量對象,指向GO,然后開始執(zhí)行代碼。

2.4.執(zhí)行代碼,根據(jù)代碼從上往下依次執(zhí)行。

var name = "why"
//通過vo-》go找到name,值改成“why”

console.log(num1)
//作用域提升,打印undefined
var num1 = 20
//同上
var num2 = 30
//同上
var result = num1 + num2
//同上
console.log(result)
//在vo-》go查找result,然后打印出來
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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