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