帶你了解JavaScript的運(yùn)行原理
了解JavaScript 是如何運(yùn)行的,以及的它的運(yùn)行機(jī)制,首先,我們要了解瀏覽器的內(nèi)核:
瀏覽器內(nèi)核
了解過(guò)的都知道:不同的瀏覽器是由不同的內(nèi)核組成,那么有哪些內(nèi)核以及我們常用的瀏覽器都使用了那些內(nèi)核:
- Gecko:早期被Netscape和Mozilla Firefox瀏覽器瀏覽器使用;
- Trident:微軟開(kāi)發(fā),被IE4~IE11瀏覽器使用,但是Edge瀏覽器已經(jīng)轉(zhuǎn)向Blink;
- Webkit:蘋(píng)果基于KHTML開(kāi)發(fā)、開(kāi)源的,用于Safari,Google Chrome之前也在使用;
- Blink:是Webkit的一個(gè)分支,Google開(kāi)發(fā),目前應(yīng)用于Google Chrome、Edge、Opera等;
所謂瀏覽器內(nèi)核,指的是瀏覽器的排版引擎,即瀏覽器引擎。引擎的工作執(zhí)行流程如下:
但是在這個(gè)執(zhí)行過(guò)程中,HTML解析的時(shí)候遇到了JavaScript標(biāo)簽,應(yīng)該怎么辦呢?
會(huì)停止解析HTML,而去加載和執(zhí)行JavaScript代碼;
當(dāng)然,為什么不直接異步去加載執(zhí)行JavaScript代碼,而要在這里停止掉呢?
所以瀏覽器希望將HTML解析的DOM和JavaScript操作之后的DOM放到一起來(lái)生成最終的DOM樹(shù),而不是頻繁的去生成新的DOM樹(shù);
那么,JavaScript代碼由誰(shuí)來(lái)執(zhí)行呢?
答案:JavaScript 引擎
JavaScript 引擎
為什么需要JavaScript引擎呢?
- 事實(shí)上我們編寫(xiě)的JavaScript無(wú)論你交給瀏覽器或者Node執(zhí)行,最后都是需要被CPU執(zhí)行的;
- 但是CPU只認(rèn)識(shí)自己的指令集,實(shí)際上是機(jī)器語(yǔ)言,才能被CPU所執(zhí)行;
- 所以我們需要JavaScript引擎幫助我們將JavaScript代碼翻譯成CPU指令來(lái)執(zhí)行;
常見(jiàn)的JavaScript 引擎有哪些呢?
- SpiderMonkey:第一款JavaScript引擎,由Brendan Eich開(kāi)發(fā)(也就是JavaScript作者);
- Chakra:微軟開(kāi)發(fā),用于IE瀏覽器;
- JavaScriptCore:WebKit中的JavaScript引擎,Apple公司開(kāi)發(fā);
- V8:Google開(kāi)發(fā)的強(qiáng)大JavaScript引擎,也幫助Chrome從眾多瀏覽器中脫穎而出;(V8 是一個(gè)強(qiáng)大的JavaScript 引擎)
V8 引擎
- V8是用C ++編寫(xiě)的Google開(kāi)源高性能JavaScript和WebAssembly引擎,它用于Chrome和Node.js等。
- 它實(shí)現(xiàn)ECMAScript和WebAssembly,并在Windows 7或更高版本,macOS 10.12+和使用x64,IA-32,ARM或MIPS處理器的Linux系統(tǒng)上運(yùn)行。
- V8可以獨(dú)立運(yùn)行,也可以嵌入到任何C ++應(yīng)用程序中。
V8 引擎執(zhí)行JavaScript 代碼的原理:
Parse模塊會(huì)將JavaScript代碼轉(zhuǎn)換成AST(抽象語(yǔ)法樹(shù)),這是因?yàn)榻忉屍鞑⒉恢苯诱J(rèn)識(shí)- JavaScript代碼;
- 如果函數(shù)沒(méi)有被調(diào)用,那么是不會(huì)被轉(zhuǎn)換成AST的;
- Parse的V8官方文檔:https://v8.dev/blog/scanner
Ignition是一個(gè)解釋器,會(huì)將AST轉(zhuǎn)換成ByteCode(字節(jié)碼)
- 同時(shí)會(huì)收集TurboFan優(yōu)化所需要的信息(比如函數(shù)參數(shù)的類型信息,有了類型才能進(jìn)行真實(shí)的運(yùn)算);
- 如果函數(shù)只調(diào)用一次,Ignition會(huì)執(zhí)行解釋執(zhí)行ByteCode;
- Ignition的V8官方文檔:https://v8.dev/blog/ignition-interpreter
TurboFan是一個(gè)編譯器,可以將字節(jié)碼編譯為CPU可以直接執(zhí)行的機(jī)器碼;
- 如果一個(gè)函數(shù)被多次調(diào)用,那么就會(huì)被標(biāo)記為熱點(diǎn)函數(shù),那么就會(huì)經(jīng)過(guò)TurboFan轉(zhuǎn)換成優(yōu)化的機(jī)器碼,提高代碼的執(zhí)行性能;
- 但是,機(jī)器碼實(shí)際上也會(huì)被還原為ByteCode,這是因?yàn)槿绻罄m(xù)執(zhí)行函數(shù)的過(guò)程中,類型發(fā)生了變化(比如sum函數(shù)原來(lái)執(zhí)行的是number類型,后來(lái)執(zhí)行變成了string類型),之前優(yōu)化的機(jī)器碼并不能正確的處理運(yùn)算,就會(huì)逆向的轉(zhuǎn)換成字節(jié)碼;
- TurboFan的V8官方文檔:https://v8.dev/blog/turbofan-jit
上面是JavaScript代碼的執(zhí)行過(guò)程
學(xué)習(xí),記錄,共勉!
到此這篇關(guān)于帶你了解JavaScript的運(yùn)行原理的文章就介紹到這了,更多相關(guān)JavaScript運(yùn)行原理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- JavaScript 運(yùn)行機(jī)制詳解再淺談Event Loop
- 一篇文章學(xué)會(huì)jsBridge的運(yùn)行機(jī)制
- Docker安裝、創(chuàng)建鏡像、加載并運(yùn)行NodeJS程序的詳細(xì)過(guò)程
- Jupyter Notebook運(yùn)行JavaScript的方法
- 解決node終端下運(yùn)行js文件不支持ES6語(yǔ)法
- visual studio code 編譯運(yùn)行html css js文件的教程
- 用Golang運(yùn)行JavaScript的實(shí)現(xiàn)示例
- 前端 JavaScript運(yùn)行原理
相關(guān)文章
詳解JavaScript中數(shù)組和字符串的lastIndexOf()方法使用
這篇文章主要介紹了詳解JavaScript中數(shù)組和字符串的lastIndexOf()方法使用,文中特別提及了IE8的兼容問(wèn)題以及for in的使用問(wèn)題,需要的朋友可以參考下2016-03-03setTimeout和setInterval的瀏覽器兼容性分析
setTimeout和setInterval的瀏覽器兼容性分析...2007-02-02slice函數(shù)的用法 之不錯(cuò)的應(yīng)用
slice函數(shù)的用法 之不錯(cuò)的應(yīng)用...2006-12-12javascript開(kāi)發(fā)技術(shù)大全-第3章 js數(shù)據(jù)類型
字符串類型(string) :由unicode字符、數(shù)字、標(biāo)點(diǎn)符號(hào)組成,在javascript中沒(méi)有char字符類型 ,即使只表示一個(gè)字符,也必須用到字符串2011-07-07JavaScript中__proto__與prototype的關(guān)系深入理解
本文將討論下對(duì)象的內(nèi)部原型(__proto__)和構(gòu)造器的原型(prototype)的關(guān)系,需要了解更多的朋友可以參考下2012-12-12js中的setInterval和setTimeout使用實(shí)例
這篇文章主要介紹了javascript中的兩個(gè)定時(shí)執(zhí)行函數(shù)setInterval和setTimeout的用法,需要的朋友可以參考下2014-05-05