在 Microsoft Edge 提供快速的 JavaScript 效能

oschina發表於2015-06-21

我們已經在 Windows 10 和 Microsoft Edge 大大地提高了 Chakra JavaScript 引擎的效能。目的是儘可能地利用現有硬體,讓你的 JavaScript 程式碼跑的更快。以便你建立的網頁能在 Microsoft Edge 中提供更好的使用者體驗。在開發過程中,我們團隊的目標之一,就是仔細觀察使用者反饋回來的資料,儘可能的讓在現有的網頁上面跑的更快些。

就在不久前, 我們曾經為 Microsoft Edge 提供,在 Windows 10 中提高 Chakra JavaScript 引擎效能的各種方案。 改善效能是永無止盡的追求,所以在本文中,我們來談一談,如何根據當今的網頁反饋回來的資料提高 Chakra’s JIT 編譯器的效能。

跨檔案指令碼內聯

現在的 JavaScript 編譯器都把行內函數當作是優化效能的關鍵因素。函式內聯是指把被呼叫的函式體插入呼叫的函式當中,就好像被呼叫的函式直接寫在呼叫的函式程式碼中一樣,因此,能節省函式呼叫和返回的開銷(比如,暫存器的儲存與恢復)。對於那些對效能要求較高的程式碼,函式內聯可以提高20-30%的效能。

在內聯過程中, 編譯器會自動權衡是否要內聯處理。 比如,有些時候,編譯器為了生成內聯程式碼,而花在收集上下文資訊上的時間,比優化過後省下來的時間還要多。或者,試圖內聯其他上下文或指令碼檔案的函式,付出的代價遠比從內聯得到的要高。

在開發 Windows 10 和 Microsoft Edge 過程中, 我們從現有的網站收集了一些資料, 以便更好的理解  Chakra 的內聯優化效果。我們從排名前 10000 的網站中, 隨機選取 f 3,000 個, 得出如下資料:

 在 Microsoft Edge 提供快速的 JavaScript 效能  在 Microsoft Edge 提供快速的 JavaScript 效能
在 Chakra中只有 30%  的函式呼叫進行內聯。 而有 48% o的函式, 由於呼叫與被呼叫分別存放在不同的指令碼檔案中, 無法內聯。 在另外一個圖表中,超過 60% 的網站沒有內聯。

在 Windows 10 和 Microsoft Edge 中,  Chakra’s JIT 編譯器和和執行管道已經優化過, 所以, Chakra 現在能夠高效地內聯跨指令碼檔案的函式, 而不會丟失過多的效能。這種方式, 允許現有網站的 JavaScript 程式碼在 Microsoft Edge 上執行的更快。

通過固定欄位提高全域性常量速度

ECMAScript6 將 const 常量值 引入到了 Javascript 語言中。Const 常量在給 Javascript 開發者帶來語言和工具的便利的同時,還使得 Javascript 編譯器可以優化查詢的新能。當一個屬性被定義為常量,編譯器可以該屬性在程式的整個生命週期都是不會發生改變的。在這個前提下,編譯器可以相應的優化,從而避免在這種屬性的查詢開銷。查詢開銷包括了檢查該屬性的型別, 結構,內部表現,找到該屬性實際儲存的值,以及檢查在程式的執行過程該值是否發生過變化等一系列開銷。而對於常量,編譯器不用執行以上任何一種檢查。

然後常量在網站正在日益增加,但是現存的大多數網站都還沒有試用常量結構。對於現在的網站,多數的常量都是被定義為一個全域性變數,然後在程式碼中到處試用. 在我們對10,000多家網站進行的一種實驗中,我們發現20%的網站都有定義整形常量的現象。而且每家網站有平均超過4處這種做法。

在 Windows 10 和 Microsoft Edge 中,我們優化了 Chakra 的解析器和 JIT 編譯器,用以識別出宣告的非常數整型變數,這些變數在程式執行期間都有定義,但是沒有變化。一旦鑑別出來,Chakra 的 JIT 編譯器生成的程式碼就可以大幅度地減小迴圈消耗,因為這樣的全域性變數在整個程式執行期間它們的值和形狀都沒有發生改變。因此將面向效能的 ECMAScript 6 中關於常數宣告的價值主張延伸到今天常數是如何廣泛地應用在網路中。

提升 try-catch 塊中程式碼的效能

在今天,使用 try-catch 是非常普遍的。但是,在實踐中並不推薦使用 try-catch,尤其對於那些對效能很敏感的程式碼。Try-catch 程式碼很難被優化,因為 try-catch 塊中的大對數操作會導致異常,然後被捕獲。這種方式使 JIT 編譯器很難得到一個精準的模型。不同的技術需要使用不同的模型,這就導致執行引擎需要建立額外的開銷來維護不同的模型。

我們所做的資料採集實驗是基於4500個熱門站點的,就此瞭解有超過96%的站點會丟擲JavaScript異常。實際上,超過50%的站點會丟擲超過10個以上的JavaScript異常。

直到Windows 10,Chakra都沒有優化try-catch塊內的程式碼。在Windows 10和Microsoft Edge中, Chakra的編譯器現在可以抽象try-catch程式碼塊內的程式碼和JIT優化的程式碼。這種情況下異常不會被丟擲,Chakra現在執行try塊內的程式碼幾乎與普通的JIT程式碼一樣(這就好像try-catch不存在一樣)。

Minified JS程式碼現在帶來大小和速度的好處

現今的 Web 通常都使用了 minified JavaScript 程式碼,這帶來了一個優勢,即減少了客戶端(瀏覽器)顯示內容的大小。在 Windows10 release 版本中,在調查一個特殊的效能問題的時候,我們發現一件事情,一些使用 minified JS 程式碼(minified JS 使用 UglifyJS)的例項,效能不及未使用 minified JS 的例項。在某些情況下,開發者在使用 minified JS 的過程中,使用了一些我們認為開發者通常不會使用的程式碼模式,這也是 Chakra 還未做優化的原因。於是,我們做了一個快速的試驗,用來檢視 Web 上使用 minified JS 的情況。我們從 10,000 個站點中隨機取樣了 4,000 個站點,下面是我們發現的資訊:

Minification on Top 4000 sites
 在 Microsoft Edge 提供快速的 JavaScript 效能  在 Microsoft Edge 提供快速的 JavaScript 效能  在 Microsoft Edge 提供快速的 JavaScript 效能
95% of the sites had some form of minified code Out of the 95%, 77% sites had some code that was minified using UglifyJS Out of the 95%, 47% of the sites used jQuery minified via UglifyJS

這個試驗確認了,在 Web 中 minified JS 程式碼的使用非常流行,由於 UglifyJS 存在於其它程式碼之中,所以它也非常廣泛的應用於現今的 Web 之中。因此,在 Windows10 和 Microsoft Edge 瀏覽器之中,我們增加了用來提升內聯的新途徑。同時,我們優化了在 Chahra 的 JIT 編譯器的一些探索法,用來確保 minified JS 程式碼執行的儘可能和沒有使用 minified JS 程式碼的版本一樣快–即便不比它們更快。基於這些改變,我們測試過,使用 UglifyJS 的單一程式碼模式的 minified JS 效能提升了大概20-50%。

Array#indexOf 優化

在Web中使用陣列的情況是非常普遍的。除了提供polyfills和幫助函式,許多非官方的JavaScript庫,嘗試著提供JavaScript語言一些標準陣列內建函式的更快的實現。理想的情況下,對於內建的部分,所有的瀏覽器都應該足夠的快,這樣,庫就可以更集中於提供polyfill和幫助API,而不是擔心在不同瀏覽器之間修復內建部分的效能問題。另一方面,開發者也不應該,僅僅為了讓一些所有JavaScript引擎實現的基本內建部分執行的更快,而不得不使用一個庫。

儘管我們離上面提到的理想情況很遠,在最近的一個資料採集的試驗中,我們嘗試著估量在現今Web中使用最多的ECMAScript 5 的內建部分。這個試驗從10,000個站點中隨機取樣大約4000個站點。我們發現,其中使用最多的前三名分別是: Array#indexOf, Array#map 和 Array#forEach。

鑑於Array內建函式在Web中的廣泛使用,在Windows10 和 Microsoft Edge中,當引擎遍歷一個陣列時,Chakra優化了獲取值的過程。當陣列中存在“洞”(hole,即不存在元素)的時候,這項優化有助於去除訪問原型鏈(extraneous overhead)和根據序號查詢數值的時候的外部開銷。這項優化提升了Chakra和Microsoft Edge中內建的 ECMAScript5 Array#indexOf 函式超過5倍的效能。

那麼,我們已經夠快了嗎?

在下面列出來的許多優化中都是來自於網路上面已經存在的資料,幫助站點在 Microsoft Edge 上面執行的更快。我們不願意去討論關於虛擬測試,還是經常被問及(Charkra)是如何在 Mircorsoft Edge 上獲得如此高的 Javascript 測試效能的。下面的圖是我們目前為止已經提交的IE11同其他流行的瀏覽器相比在 Microsoft Edge 上得到效能加強的 Javascript 測試結果。

在 Microsoft Edge 提供快速的 JavaScript 效能 在 Microsoft Edge 提供快速的 JavaScript 效能

所有的測試基準都是在64位Window 10 技術預覽版上面執行的64位瀏覽器收集而得.

系統資訊:HP Compaq 8100 Elite with Intel(R) Core(TM) i7

CPU 860 @ 2.80GHz (4 cores), 12GB RAM

這張圖說明了什麼?在 Microsoft Edge 上 Charkra 比 IE11 更快。仔細看,Chakra 在以下的這些的測試中通過 Microsoft Edge 獲得了效能提升:

Benchmark                                                 Microsoft Edge 的效能改進超過了 IE11

Jet Stream                                                    Apple 超過了1.5倍

Octane 2.0                                                    Google 超過了2.25倍

注意:你會好奇在這個效能測試中為什麼是了 64 位瀏覽器而不是 32 位瀏覽器,原因是不像 IE11 Microsoft Edge 需要執行在 64 位的平臺下。所有的流行的 64 位 Javascript 引擎相比較 32 位平臺執行有一點點慢,選擇 64 位平臺可以提供一些安全特性,在這篇部落格中得到了補充。

然而在贏得了跑分中並沒有使我們感到很滿意,關鍵是為了提升 Javascript 的效能從 IE11 開始 Microsoft Edge 已經走過了很長的一段路程,就像測試已經存在了。如我們開始提到的,效能是一個不懈的追求。我們會繼續挖掘 Javascript 在 Microsoft Egde 中得效能極限。請繼續保持反饋幫助我們提升。您可以在網站上提交 bug,在使用者之聲上提交反饋,或者在 twitter 上面的 @MSEdgeDev 為我們提供援助。

– Gaurav Seth, Principal PM Lead, Chakra

相關文章