重要的事情提早说: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 版本后支持app
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)