重要的事情提早说:Hermes引擎是Facebook研发,在React-Native Android端用于替换JavaScript Core的JavaScript引擎。Hermes引擎的优点是适合移动端的轻量级JavaScript引擎,使用aot编译,能够减小Android端内存使用,减少安装包大小,提高执行效率。react
JavaScript引擎是一个专门处理JavaScript脚本的虚拟机,通常会附带在网页浏览器之中。android
V8(Google)、JavaScriptCore(Apple)、SpiderMonkey(Firefox)react-native
Weex,Android:V8,iOS:JavaScriptCore浏览器
RN,Android:JavaScriptCore(Hermes、V8),iOS:JavaScriptCore(Apple要求)babel
注:Hermes Engine在React-native 0.60.2 版本后支持ide
(截取自code.fb.com)性能
传统JavaScript引擎一般是以上图的模式完成代码执行的,编译阶段只完成babel转义和minify压缩,产物仍是JavaScript脚本,解释与执行的任务都须要在运行时完成(如V8引擎,还会在运行时将JavaScript编译为本地机器码)很明显缺点就是在运行时须要边解释边执行,甚至须要占用系统资源执行编译任务。字体
(截取自code.fb.com)gradle
Hermes引擎使用了aot编译的方式,将解释和编译过程前置到编译阶段,运行时只完成机器码的执行,大大提升了运行效率。优化
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 | 支持 |
Debug模式下Hermes不开启预编译以支持Hot Reload,缺点是Release模式下全部Hermes引擎优点都不存在,甚至由于无JIT致使性能还要差于原有引擎。但开发者模式并不追求性能,而更追求调试效率。
Debug模式内置libhermes-inspector.so,支持Chrome inspect的使用,支持DevTools协议,比原有RN调试体验更佳(应用内代理,不能同步调试原生调用)
Hermes支持ES6,紧跟最新的JavaScript规范。为了优化引擎大小,不支持RN程序中使用较少的语言特性,如本地eval()。
(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: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%
面对Flutter的咄咄攻势,React-Native终于作出了一些改变,Hermes做为一款适合移动端的JavaScript引擎,确实有其性能优点,但愿经过本文可以让你更加了解Hermes。