寫給小白的JavaScript引擎指南
關(guān)于本文標(biāo)題,我并不認(rèn)為參與寫或者讀本文的人是白癡。但是有時(shí)某個(gè)話題會(huì)讓你覺得自己就像個(gè)白癡一樣,而 JavaScript 引擎就是這些話題之一,至少對(duì)于我來說是這樣。
有時(shí)編寫 Web 應(yīng)用的代碼會(huì)感覺充滿魔力,因?yàn)槲覀冎皇菍懥艘幌盗凶址湍茉跒g覽器里看到效果了。但是理解魔法背后的技術(shù),可以幫助你更好地提高編程技巧。至少當(dāng)你試圖解釋在 JavaScript 驅(qū)動(dòng)的 web 或移動(dòng)應(yīng)用的幕后發(fā)生了什么的時(shí)候,會(huì)覺得自己不那么白癡了。
很多年前,那是我還是個(gè)研究生講師,向一個(gè)教授抱怨還沒有掌握那些特別難懂的法語語法點(diǎn),可以教給我的本科學(xué)生。我記得當(dāng)時(shí)她說的話:“有時(shí)候,學(xué)習(xí)某個(gè)事物的唯一方式就是教授它?!?/p>
嘗試向工程師解釋 NativeScript 是如何通過 JavaScript 引擎在幕后工作、在運(yùn)行時(shí)連接調(diào)用原生的 APIs——面對(duì)這樣一件復(fù)雜的工作很容易在一片雜草中迷失方向。事實(shí)上,任何 JavaScript 開發(fā)者都應(yīng)該對(duì)我們每天使用的這門技術(shù)基礎(chǔ)的引擎感到好奇?,F(xiàn)在我們一起來仔細(xì)分析下 JavaScript 引擎到底做了什么,為什么不同的平臺(tái)使用不同引擎,多年來它們是如何發(fā)展的,以及作為開發(fā)者我們?yōu)槭裁匆P(guān)注這些。
首先,一些專業(yè)術(shù)語
“JavaScript 引擎”通常被稱作一種 虛擬機(jī)?!疤摂M機(jī)”是指軟件驅(qū)動(dòng)的給定的計(jì)算機(jī)系統(tǒng)的模擬器。有很多類型的虛擬機(jī),它們根據(jù)自己在多大程度上精確地模擬或代替真實(shí)的物理機(jī)器來分類。
例如,“系統(tǒng)虛擬機(jī)”提供了一個(gè)可以運(yùn)行操作系統(tǒng)的完整仿真平臺(tái)。Mac 用戶很熟悉的 Parallels 就是一個(gè)允許你在 Mac 上運(yùn)行 Windows系統(tǒng)虛擬機(jī)。
另一方面,“進(jìn)程虛擬機(jī)”不具備全部的功能,能運(yùn)行一個(gè)程序或者進(jìn)程。Wine 是一個(gè)允許你在 Linux 機(jī)器上運(yùn)行 Windows 應(yīng)用的進(jìn)程虛擬機(jī),但是并不在 Linux 中提供完整的 Windows 操作系統(tǒng)。
JavaScript 虛擬機(jī)是一種進(jìn)程虛擬機(jī),專門設(shè)計(jì)來解釋和執(zhí)行的 JavaScript 代碼。
注意:要區(qū)別在瀏覽器中排布頁面布局的 布局引擎 和解釋和執(zhí)行代碼的底層 JavaScript 引擎是非常重要的。在 這里 可以找到一個(gè)很好的闡釋。
那么,確切來講,到底什么是 JavaScript 引擎,它做了什么?
JavaScript 引擎的基本工作是把開發(fā)人員寫的 JavaScript 代碼轉(zhuǎn)換成高效、優(yōu)化的代碼,這樣就可以通過瀏覽器進(jìn)行解釋甚至嵌入到應(yīng)用中。事實(shí)上,JavaScriptCore 自稱為“優(yōu)化虛擬機(jī)”。
更準(zhǔn)確地講,每個(gè) JavaScript 引擎都實(shí)現(xiàn)了一個(gè)版本的 ECMAScript,JavaScript 是它的一個(gè)分支。隨著 ECMAScript 的不斷發(fā)展,JavaScript 引擎也不斷改進(jìn)。之所以有這么多不同的引擎,是因?yàn)樗鼈兠總€(gè)都被設(shè)計(jì)運(yùn)行在不同的 web 瀏覽器、headless 瀏覽器、或者像 Node.js 那樣的運(yùn)行時(shí)環(huán)境中。
你也許熟悉 web 瀏覽器,那什么是 headless 瀏覽器呢?它是一個(gè)沒有圖形用戶界面的 web 瀏覽器。它們?cè)趯?duì) web 產(chǎn)品進(jìn)行自動(dòng)化測(cè)試時(shí)十分有用。一個(gè)很棒的例子就是 PhantomJS。那 Node.js 又和 JavaScript 引擎有什么關(guān)系?Node.js 是一個(gè)異步的、事件驅(qū)動(dòng)的框架,讓你在服務(wù)器端可以使用 JavaScript。既然他們是驅(qū)動(dòng) JavaScript 的工具,所以它們也是由 JavaScript 引擎驅(qū)動(dòng)。
按照上述關(guān)于虛擬機(jī)的定義,把 JavaScript 引擎稱作進(jìn)程虛擬機(jī)就很好理解了,因?yàn)樗奈ㄒ坏哪康木褪亲x取和編譯 JavaScript 代碼。這并不意味著它只是個(gè)簡(jiǎn)單的引擎。比如,JavaScriptCore 就有六個(gè)“構(gòu)建模塊”可以分析、解釋、優(yōu)化、垃圾回收 JavaScript 代碼。
它是如何工作的?
當(dāng)然,這決定于引擎。吸引我們注意的兩個(gè)主要的引擎都利用了 NativeScript ,它們分別是 WebKit 的 JavaScriptCore 和 Google 的 V8 引擎。這兩個(gè)引擎使用不同的方式處理代碼。
JavaScriptCore 執(zhí)行 一系列步驟 來解釋和優(yōu)化腳本:
它進(jìn)行詞法分析,就是將源代碼分解成一系列具有明確含義的符號(hào)或字符串。
然后用語法分析器分析這些符號(hào),將其構(gòu)建成語法樹。
接著四個(gè) JIT(Just-In-Time)進(jìn)程開始參與進(jìn)來,分析和執(zhí)行解析器所生成的字節(jié)碼。
什么?簡(jiǎn)單來說,JavaScript 引擎會(huì)加載你的源代碼,把它分解成字符串(又叫做分詞),再 把這些字符串轉(zhuǎn)換 成編譯器可以理解的字節(jié)碼,然后執(zhí)行這些字節(jié)碼。
Google 的 V8 引擎 是用 C++ 編寫的,它也能夠編譯并執(zhí)行 JavaScript 源代碼、處理內(nèi)存分配和垃圾回收。它被設(shè)計(jì)成由兩個(gè)編譯器組成,可以把源碼直接編譯成機(jī)器碼:
Full-codegen:輸出未優(yōu)化代碼的快速編譯器
Crankshaft: 輸出執(zhí)行效率高、優(yōu)化過的代碼的慢速編譯器
如果 Crankshaft 確定需要優(yōu)化的代碼是由 Full-codegen 生成的未優(yōu)化代碼,它就會(huì)取代 Full-codegen,這個(gè)過程叫做“crankshafting”。
一旦編譯過程中產(chǎn)生了機(jī)器代碼,引擎就會(huì)向?yàn)g覽器暴露所有的數(shù)據(jù)類型、操作符、對(duì)象、在 ECMA 標(biāo)準(zhǔn)中指定的函數(shù)、或任何運(yùn)行時(shí)需要使用的東西,NativeScript 就是如此。
有哪些 JavaScript 引擎?
有一大堆令人眼花繚亂的 JavaScript 引擎可以用來解釋、分析和執(zhí)行你的客戶端代碼。每個(gè)瀏覽器版本發(fā)布時(shí),它的 JavaScript 引擎都可能有所改變或優(yōu)化以跟上 JavaScript 代碼執(zhí)行技術(shù)的狀況的變化。
你還沒被這些瀏覽器引擎的名字完全弄糊涂之前,請(qǐng)記住很多市場(chǎng)營銷的元素被加入了這些引擎和以它們?yōu)榛A(chǔ)的瀏覽器。這篇對(duì) JavaScript 編譯 十分有用的分析 中,作者諷刺地指出:“你所不知道的是,編譯器大約有 37% 是由市場(chǎng)營銷構(gòu)成的,對(duì)編譯器進(jìn)行品牌重塑也是你能做的為數(shù)不多的事情之一,智慧的市場(chǎng)營銷,故而有了一系列名字:SquirrelFish、Nitro、SFX……”。
在牢記營銷對(duì)命名和重命名這些引擎的影響的同時(shí),注意到幾件在 JavaScript 引擎發(fā)展史上的重大事件是很有用的。我為你做了一個(gè)便于理解的圖表:
Browser, Headless Browser, or Runtime | JavaScript Engine |
---|---|
Mozilla | Spidermonkey |
Chrome | V8 |
Safari | JavaScriptCore |
IE and Edge | Chakra |
PhantomJS | JavaScriptCore |
HTMLUnit | Rhino |
TrifleJS | V8 |
Node.js | V8 |
Io.js* | V8 |
*JavaScriptCore 被改寫為 SquirrelFish,升級(jí)版本為 QuirrelFish Extreme,也叫做 Nitro。然而,構(gòu)成 Webkit 實(shí)現(xiàn)基礎(chǔ)的 JavaScript 引擎就是 JavaScriptCore(比如 Safari)。
**iOS 開發(fā)者應(yīng)該要知道移動(dòng)設(shè)備的 Safari 使用 Nitro,但是 UIWebView 不包括 JIT 編譯,所以體驗(yàn)會(huì)慢一些。然而開發(fā)人員可以在 iOS8 中使用包含 Nitro 的 WKWebView,使用體驗(yàn) 明顯 變快?;旌弦苿?dòng)應(yīng)用程序的開發(fā)人員應(yīng)該能松口氣了。
*最終 io.js 從 Node.js 分離開的原因之一就是為了支持 V8 版本的引擎。這仍然是一個(gè)挑戰(zhàn),正如 這里 講述的。
我們?yōu)槭裁匆P(guān)注?
JavaScript 引擎的代碼解析和執(zhí)行過程的目標(biāo)就是在最短時(shí)間內(nèi)編譯出最優(yōu)化的代碼。
最重要的是,這些引擎的演進(jìn)與我們對(duì)發(fā)展 web 和 移動(dòng)平臺(tái)的不斷探究息息相關(guān),讓它們盡可能具有高性能,是相輔相成的。為了追蹤這種演進(jìn),你可以看到各種各樣的引擎在基準(zhǔn)圖中是如何表現(xiàn)的,就好像 arewefastyet.com 總結(jié)的。例如,比較 Chrome 在搭載 V8 引擎與 non-Crankshafted 引擎時(shí)的表現(xiàn)就很有趣。
任何一個(gè) web 開發(fā)者都要意識(shí)到,我們努力編寫、調(diào)試和維護(hù)的代碼在不同瀏覽器中執(zhí)行效果必然有所差異。為什么某段代碼在一個(gè)瀏覽器上工作得很慢,但在另一個(gè)上卻快得多?
同樣地,移動(dòng)開發(fā)者,尤其是使用 webview 顯示頁面內(nèi)容的混合移動(dòng)應(yīng)用開發(fā)者,或者那些使用像 NativeScript 這種運(yùn)行時(shí)環(huán)境的開發(fā)者,想知道是什么引擎在解釋執(zhí)行他們的 JavaScript 代碼。移動(dòng) web 開發(fā)者應(yīng)該注意到那些小小設(shè)備上的瀏覽器所具備的各種局限性和可能性。作為一個(gè)想持續(xù)發(fā)展的 web、移動(dòng)或應(yīng)用程序開發(fā)人員,時(shí)刻關(guān)注 JavaScript 引擎的變化會(huì)帶給你超值回報(bào)。
總結(jié):
js 中的基本數(shù)據(jù)類型 undefined null boolean number string
js 中的一種復(fù)雜數(shù)據(jù)類型 object 它是所有對(duì)象的基礎(chǔ)類型
js 和其他語言一樣擁有9種基本的控制語句
js 中的函數(shù)無需指定返回值,實(shí)際上未指定返回值的函數(shù)返回的是undefined
js 中的參數(shù)可以隨意的傳遞 注意arguments[] 數(shù)組 它可以幫助你
js 中的函數(shù)是不能重載的,但是你可以模仿。
- jsp搜索引擎
- javascript 多種搜索引擎集成的頁面實(shí)現(xiàn)代碼
- 為JavaScript提供睡眠功能(sleep) 自編譯JS引擎
- silverlight線程與基于事件驅(qū)動(dòng)javascript引擎(實(shí)現(xiàn)軌跡回放功能)
- javascript模版引擎-tmpl的bug修復(fù)與性能優(yōu)化分析
- js動(dòng)畫(animate)簡(jiǎn)單引擎代碼示例
- 瀏覽器的JavaScript引擎的識(shí)別方法
- javascript輕量級(jí)模板引擎juicer使用指南
- Powershell小技巧之使用Jint引擎在PowerShell中執(zhí)行Javascript函數(shù)
- javascript引擎長時(shí)間獨(dú)占線程造成卡頓的解決方案
- 基于jQuery的JavaScript模版引擎JsRender使用指南
- 教你使用javascript簡(jiǎn)單寫一個(gè)頁面模板引擎
- js如何判斷訪問是來自搜索引擎(蜘蛛人)還是直接訪問
- 黑帽seo劫持程序,js劫持搜索引擎代碼
相關(guān)文章
js學(xué)習(xí)總結(jié)之DOM2兼容處理順序問題的解決方法
這篇文章主要為大家詳細(xì)介紹了DOM2兼容處理順序問題的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07JS實(shí)現(xiàn)移動(dòng)端點(diǎn)擊按鈕復(fù)制文本內(nèi)容
本文通過實(shí)例代碼給大家介紹了移動(dòng)端點(diǎn)擊按鈕復(fù)制文本內(nèi)容 ,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-07-07requirejs按需加載angularjs文件實(shí)例
本篇文章主要介紹了requirejs按需加載angularjs文件實(shí)例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-06-06使用JS簡(jiǎn)單實(shí)現(xiàn)apply、call和bind方法的實(shí)例代碼
在JavaScript中,call、apply和bind是Function對(duì)象自帶的三個(gè)方法,這三個(gè)方法的主要作用是改變函數(shù)中的this指向,下面這篇文章主要給大家介紹了關(guān)于如何使用JS簡(jiǎn)單實(shí)現(xiàn)apply、call和bind方法的相關(guān)資料,需要的朋友可以參考下2022-02-02Add a Picture to a Microsoft Word Document
Add a Picture to a Microsoft Word Document...2007-06-06通過JS 獲取Mouse Position(鼠標(biāo)坐標(biāo))的代碼
最近我發(fā)現(xiàn)在webpage中獲取空間的絕對(duì)坐標(biāo)時(shí),如果有滾動(dòng)條就會(huì)有錯(cuò),后來用無名發(fā)現(xiàn)的方法得以解決。2009-09-09IScroll5 中文API參數(shù)說明和調(diào)用方法
IScroll是移動(dòng)頁面上被使用的一款仿系統(tǒng)滾動(dòng)插件。IScroll5相對(duì)于之前的IScroll4改進(jìn)了許多,使得大家可以更方便的定制所需的功能了。2016-05-05JavaScript實(shí)現(xiàn)表格動(dòng)態(tài)變色
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)表格動(dòng)態(tài)變色,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09Javascript 獲取鏈接(url)參數(shù)的方法
Javascript 獲取鏈接(url)參數(shù)的實(shí)現(xiàn)方法2009-02-02