自從 Google 的 Flutter 發佈以後,Facebook 對 React-Native 的迭代開始快了起來,優化 React-Native 的性能表現,避免被 Flutter 比下去。最近一個比較大的動做是開源了一個 JavaScript 引擎,並將其包含到 React-Native 中。那麼這款引擎它有什麼不一樣,相比 V八、JSC 這些 JavaScript 引擎又有什麼優點呢,如今本文來爲你揭曉。react
重要的事情提早說:Hermes 引擎是 Facebook 研發,在 React-Native Android 端用於替換 JavaScript Core 的 JavaScript 引擎。Hermes 引擎的優點是適合移動端的輕量級 JavaScript 引擎,使用 aot 編譯,能夠減小 Android 端內存使用,減少安裝包大小,提高執行效率。android
JavaScript 引擎是一個專門處理 JavaScript 腳本的虛擬機,通常會附帶在網頁瀏覽器之中。react-native
3. 主流 JavaScript 引擎瀏覽器
V8(Google)、JavaScriptCore(Apple)、SpiderMonkey(Firefox)babel
4. RN 中的 JavaScript 引擎ide
Weex,Android:V8,iOS:JavaScriptCore性能
RN,Android:JavaScriptCore(Hermes、V8),iOS:JavaScriptCore(Apple 要求)字體
注:Hermes Engine在React-native 0.60.2 版本後支持gradle
預編譯字節碼(引擎加載二進制代碼效率高於運行JS腳本)優化
無 JIT 編譯器(減少了引擎大小,優化內存佔用,但直接運行 JS 腳本的性能差於 V8 和 JSC)
針對移動端的垃圾回收策略
傳統 JavaScript 引擎一般是以上圖的模式完成代碼執行的,編譯階段只完成 babel 轉義和 minify 壓縮,產物仍是 JavaScript 腳本,解釋與執行的任務都須要在運行時完成(如 V8 引擎,還會在運行時將 JavaScript 編譯爲本地機器碼)很明顯缺點就是在運行時須要邊解釋邊執行,甚至須要佔用系統資源執行編譯任務。
Hermes 引擎使用了 aot 編譯的方式,將解釋和編譯過程前置到編譯階段,運行時只完成機器碼的執行,大大提升了運行效率。
升級 React-Native 及相關庫升級(成本較小)
由於 React-Native 0.60.x 變動爲依賴 AndroidX,因此 Android 項目須要使用 28 以上版本編譯,適配 Android 高版本,且須要遷移到 AndroidX(成本較大)
修改 build.gradle,添加 Hermes 相關屬性及依賴(成本較小)
Hermes 引擎預編譯後的產物與RN原方式相同,都是在 assets 文件夾下生成的 index.android.bundle 文件。RN 原方式中 index.android.bundle 是通過壓縮的 JavaScript 腳本文件,Hermes 預編譯後則是二進制文件。由於只有產物文件格式的區別,並無修改原有JS Bundle 的加載方式,因此 CodePush 能夠繼續使用。
目前 code-push 的兩種發佈模式支持狀況:
發佈方式 | 是否支持 | 備註 |
code-push release-react |
支持,但沒法產生預編譯腳本產物 |
需依賴react-native bundle命令完成腳本打包,該命令尚不支持預編譯 |
code-push release |
支持 |
9. 調試效率
Debug 模式下 Hermes 不開啓預編譯以支持 Hot Reload ,缺點是 Release 模式下全部Hermes 引擎優點都不存在,甚至由於無 JIT 致使性能還要差於原有引擎。但開發者模式並不追求性能,而更追求調試效率。
Debug 模式內置 libhermes-inspector.so ,支持 Chrome inspect 的使用,支持 DevTools 協議,比原有 RN 調試體驗更佳(應用內代理,不能同步調試原生調用)
Hermes 支持 ES6,緊跟最新的 JavaScript 規範。爲了優化引擎大小,不支持 RN 程序中使用較少的語言特性,如本地 eval()。
▍包大小分析
原包大小 20MB(JSC)
新包大小 18MB(Hermes)
包大小減少 2MB,總體減小 2MB / 20MB = 10%
分析具體包大小減少的緣由能夠發現,包內容二者只有 lib 大小和 assets 的大小存在差別。
對比 lib 內容,發現大小差距主要是由 libjsc.so 和 libhermes.so 二者的差距致使的,即 Hermes 引擎的大小。
對比 assets 內容,發現大小變化主要由 index.android.bundle ,即 JavaScript 打包產物引發,Hermes 模式下反而更大的緣由是進一步編譯爲二進制代碼。
二者影響疊加致使總體減少,包大小獲得優化。(支持的平臺越多,包體積優化效果越好)
▍內存分析
實驗方法:在相同的業務頁面穩定狀態下經過 Memory Profiler 查看內存佔用狀況
原包平均內存佔用 210MB
新包平均內存佔用 190MB
內存佔用平均減少20MB以上,總體減少20MB / 210MB = 10%
分析 Profiler 數據能夠發現,內存優化主要發生在 Code 內存區。
Google 官方文檔中對內存 Code 區的描述:
Code:您的應用用於處理代碼和資源(如 dex 字節碼、已優化或已編譯的 dex 碼、.so 庫和字體)的內存。
聯繫到上個章節中包大小分析中 libhermes.so 尺寸的減少,能夠很容易想到,內存佔用的減小就是由於 .so 對內存佔用的減少。另外二者對 JavaScript 內存的佔用也有細微差異,可是能夠忽略不計。
▍TTI性能
TTI:Time to Interactive,用戶可交互時間,啓動到頁面渲染完成而且能夠正常響應用戶的輸入的時間,衡量用戶體驗的移動端指標。
值得吐槽的是,在 iOS 版本的 Pref Monitor 中直接就包含了這個指標的顯示,可是 Android 版本的 Pref Monitor 只有四個指標,且並無 TTI 這一指標。
在 Android 平臺上能夠經過 RN 提供的 ReactFindViewUtil 類獲取 RN 組件對應的原生組件,註冊對應的渲染回調,在控件渲染完成時記錄TTI結束時間。
原包 TTI 829ms
新包 TTI 694ms
TTI 減小 135ms,總體減小 135ms / 829ms = 16%
面對 Flutter 的咄咄攻勢,React-Native 終於作出了一些改變,Hermes 做爲一款適合移動端的 JavaScript 引擎,確實有其性能優點,但願經過本文可以讓你更加了解 Hermes。
本文首發自普惠出行產品技術 (ID:pzcxtech)