前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >干货 | 加载速度提升15%,携程对RN新一代JS引擎Hermes的调研

干货 | 加载速度提升15%,携程对RN新一代JS引擎Hermes的调研

作者头像
携程技术
发布于 2019-08-23 01:31:44
发布于 2019-08-23 01:31:44
5.4K03
代码可运行
举报
文章被收录于专栏:携程技术携程技术
运行总次数:3
代码可运行

作者简介

储贻锋,携程无线平台研发部基础框架组资深Android研发,目前主要负责CRN Android端和携程Android基础架构的维护与开发工作。

引言

Facebook在ChainReact2019大会上正式推出了新一代JavaScript执行引擎Hermes。Hermes是个轻量级的JS引擎,专门对Android上运行ReactNative进行了优化。我们第一时间在 CRN 项目中集成了Hermes, 并做了深度调研。

一、Hermes介绍

自ReactNative推出以来,有大量的APP接入并使用,其中也包括大型应用的主流程业务。随着业务复杂度不断上升,性能问题变得无法忽视。

在分析性能数据时,Facebook团队发现 JavaScript 引擎是影响启动性能和应用包体积的重要因素。由于JavaScriptCore最初是为桌面浏览器端设计,相较于桌面端,移动端能力有太多的限制,为了能从底层对移动端进行性能优化,Facebook团队选择自建JavaScrip引擎,设计了Hermes,限于iOS AppStore审核限制,目前仅用于Android平台。

Chain React大会上官方给出了Hermes引擎一组数据:

  • 从页面启动到用户可操作的时间长短(Time To Interact:TTI),从4.3s减少到2.01s
  • App的下载大小,从41MB减少到22MB
  • 内存占用,从185MB减少到136MB

CRN先前做过框架代码拆分和预加载、业务代码懒加载、业务代码预加载等性能优化方案,正困惑于如何更近一步进行性能优化。当看到Hermes这三个关键指标都有了显著的提高,非常激动,觉得Hermes是非常好的一个方向,接下来我们就来了解Hermes的使用和实测性能数据。

二、快速上手Hermes

Faceback团队已经将Hermes工具上传到了npm : hermesvm。hemres工具可以直接运行JS代码、转换字节码并且提供非常多的参数进行调优控制。

这里介绍一下hermesvm执行JS代码和转换bytecode功能。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 创建hermes_test文件,内容:print("This is Hermes Demo");
vim hermes_test.js

// 直接执行纯文本js
~/node_modules/hermesvm/osx-bin/hermes hermes_test.js
This is Hermes Demo

// 转换成bytecode
~/node_modules/hermesvm/osx-bin/hermes --emit-binary hermes_test.js -out hermes_test.hbc

// 执行字节码
~/node_modules/hermesvm/osx-bin/hermes hermes_test.hbc
This is Hermes Demo

三、Hermes是如何优化的?

主流JavaScript引擎,例如JSC、V8、SpiderMonkey等几乎都是为了桌面端浏览器服务的,Hermes针对移动终端设备的特点做了一些优化,其中最重要的我们认为是以下两点:

3.1 字节码预编译

现代主流的JavaScript引擎在执行一段js代码的大概流程是:

  • 先读取源码文件
  • 解析源代码并转换成字节码(bytecode)
  • 最后执行

在运行时解析源码转换字节码是一种时间浪费,所以Hermes选择预编译的方式在编译期间生成字节码。这样做一方面避免了不必要的转换时间,另一方面多出的时间可以用来优化字节码,从而提高执行效率。

3.2 放弃JIT

为了加快执行效率,现在主流的JavaScript引擎都会使用一个JIT编译器在运行时通过转换成机器码的方式优化JS代码。Faceback团队认为JIT编译器有主要俩个问题:

  • 要在启动时候预热,对启动时间有影响;
  • 会增加引擎size大小和运行时内存消耗;

基于这俩点对性能指标的影响,Faceback团队决定不实现JIT编译器。

这里所谓放弃JIT,有两点需要再解释一下:

  • 纯文本JS代码执行效率降低。放弃JIT,是指放弃运行时Hermes引擎对纯文本JS代码的编译优化。我们的验证数据也表面,纯文本的JS代码执行,Hermes引擎明显比JavaScriptCore慢。
  • 对RN代码的动态性无影响。由于Hermes仍然可以执行纯文本的JS代码,并且可以支持动态读取bytecode, 因此对RN的动态性并无影响。

四、如何集成Hermes?

4.1 从新创建工程集成
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1. 升级最新react-native-cli
npm install -g react-native-cli

2.初始化最新react-native工程,最新版为0.60.3
react-native init HermesDemo

3. 开启hermes, 编辑HermesDemo工程 android/app/build.gradl文件
 project.ext.react = [
      entryFile: "index.js",
-     enableHermes: false  // clean and rebuild if changing
+     enableHermes: true  // clean and rebuild if changing
  ]

4. 使用Relase包体验Hermes带来的速度提升
react-native run-android --variant release
4.2 从源码集成
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
git clone https://github.com/facebook/react-native.git // 需要切换到Hermes release节点,比如:eec4dc6
cd react-native
npm install
./gradlew :RNTester:android:app:installHermesRelease // 使用生产环境hermes
4.3 Hermes集成过程分析

分析react-native react.gradle源码可以看到,如果打开了Hermes开关,会在原先打包RN代码的bundleXXXJsAndAsset task后面追加执行一段Hermes转换命令: hermes --emit-binary -out xxx。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
...
// 1. 执行标准RN打包
commandLine(*nodeExecutableAndArgs, cliPath, bundleCommand, "--platform", "android", "--dev", "${devEnabled}",
                    "--reset-cache", "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir,
                    "--sourcemap-output", jsPackagerSourceMapFile, *extraArgs)
...
...
// 2. 将打包好的jsbundle文件转换成字节码
if (enableHermes) {
    commandLine(getHermesCommand(), "-emit-binary", "-out", jsBundleFile, jsBundleFile, *hermesFlags)
}
...
4.4 执行过程分析

为了进一步抽象JavaScript执行层,RN底层创建了JSExecutor和Runtime接口,并把大部分业务逻辑放到了实现了JSExecutor的JSIExcutor.cpp中。对于JavaScript执行引擎来说只需要实现Runtime接口即可对接RN框架。

JavaScriptCore的Runtime实现类是JSCRuntime。相应的,此次Hermes升级,底层创建了HermesRuntime。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// JSCRuntime.cpp jsc Runtime
class JSCRuntime : public jsi::Runtime

// hermes.h hermes Runtime
class HermesRuntime : public jsi::Runtime...

每一种JSExecutor都提供了创建类XXXExecutorFactory来创建相应实例,并且提供了相应的Java对象。

RN框架在初始化ReactInstanceManager的时候需要传入JavaScriptExecutorFactory。如果要切换JavaScript执行引擎只需要在ReactInstanceManager创建的时候做控制即可。

官方的控制流程是,优先加载jscexecutorso,如果成功则使用JSCRuntime,否则使用HermesRuntime。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private JavaScriptExecutorFactory getDefaultJSExecutorFactory(String appName, String deviceName) {
    try {
      // If JSC is included, use it as normal
      SoLoader.loadLibrary("jscexecutor");
      return new JSCExecutorFactory(appName, deviceName);
    } catch(UnsatisfiedLinkError jscE) {
      // Otherwise use Hermes
      return new HermesExecutorFactory();
    }
  }

由此可见无论是对于RN JS代码的打包还是Native代码逻辑的更改,升级Hermes的成本都非常低。

五、Hermes,JavaScriptCore,V8 的对比

通过上面的Hermes集成分析可知,Hermes对整个RN原有架构的侵入是极少的,甚至做到了可插拔式接入。我们很快将Hermes集成到携程CRN框架,并和原先的JavaScriptCore引擎以及社区提供的V8引擎做了比较。

经过我们的数据验证,Faceback团队提出的关键性指标相较于原先的JSC都有了显著提高。

  • 首屏渲染速度:bytecode代码执行情况下,Hermes比JavaScriptCore要快。在携程App中,拿门票业务做了验证,在做了预加载的情况下,首屏加载速度依然可以提升约15%。而V8的表现就非常糟糕了。
  • Native so size:RN所依赖的必要so库,Hermes比JavaScriptCore减少了约16%(单armeabi架构压缩后降低了0.5M左右),V8则要远大于Hermes和JavaScriptCore。
  • 内存:拿RNTester工程测试进入RN页面滑动进入若干页面并退出之后,内存的波动情况比较可以看到,V8和Hermes内存增长要更加平滑。
  • CPU:拿RNTester工程测试进入RN页面滑动进入若干页面并退出之后,对比CPU波动情况。Hermes明显好于V8和JavaScriptCore。

六、Hermes引擎的动态性

另外通过我们的测试,Hermes在执行字节码和文本JS上有一些很有意思的特性,这些特性让升级成本变得非常低:

  • Hermes支持执行纯文本的js
  • 支持动态加载纯文本js或者bytecode
  • 支持bytecode和纯文本js混合使用:比如a.hbc是bytecode,模块中引用了b.js,b模块是纯文本js。在加载的时候可以先加载a.hbc文件,然后加载b.js文件。可正常执行。

七、Hermes目前的问题

Hermes诸多优点让我们团队非常兴奋,几乎觉得应该立马把JavaScriptCore下掉,更换至Hermes。但随着测试和集成的进行,Hermes带来的问题逐渐显现。

7.1 bytecode文件占用size过大问题

Hermes编译的字节码文件比纯文本js文件增大100%。

携程旅行App的安装包中有20MB(7z压缩后)左右的RN业务代码,如果都编译成bytecode,将会再增加20MB大小,这是无法接受的。另外,动态下发RN增量包时,由于是二进制文件diff,差分效率极低。

为了解决这个问题,我们根据Hermes的特性,转变思路,将Hermes的bytecode编译放到客户端去做,客户端同时存储js和bytecode文件,如果有bytecode编译完成则使用Hermes,否则仍然使用JavaScriptCore。

Hermes开源项目提供了编译bytecode的complieJS方法,但这部分代码没有默认打包到RN的Hermes引擎中,我们稍加整合、封装,通过JNI暴露出来,供业务使用。

拿最大的RN业务包(1100个文件,6.5MB大小),做测试,后台线程执行,小米9 Android10耗时2.49秒;三星S6edge+ android 7.0 耗时6秒。由于bytecode不是必须,因此该耗时尚可接受。

7.2 执行纯文本js耗时长

在客户端将纯文本js转换成bytecode之前,我们让Hermes加载纯文本。但实际测试下来,发现Hermes加载纯文本的性能比JavaScriptCore要慢将近30%。主要原因是Hermes删除JIT功能,致使对纯文本js代码运行变慢。

7.3缓存问题

我们对原生RN框架做了大量的优化,缓存使用过的JS执行引擎是优化过程非常重要的一环。

拿门票页面举例来说,如果用户启动App,第一次进入门票业务将会使用一个全新的JavaScript引擎并从磁盘读取文件、加载文件、执行JS代码。用户退出门票页面之后该引擎被缓存,如果用户再一次进入将会使用缓存的引擎,不用重新读取、加载和执行,仅仅需要创建相关JS对象并渲染即可。

遗憾的是,测试Hermes的缓存的时候,我们发现使用缓存的Hermes引擎加载业务代码表现非常一般,甚至某些情况下比第一次加载还要慢。而使用缓存的JavaScriptCore引擎,第二次打开页面的速度与打开纯native页面的速度几乎相当,并且表现相当稳定。

为什么使用缓存的Hermes引擎打开页面速度不理想,可能和Hermes的设计有关,我们还在进一步分析中。

八、总结与展望

  • 从目前情况来看,在解决缓存问题之前,我们无法在线上版本直接引入Hermes。
  • 解决缓存问题之后,可以采用JavaScriptCore+Hermes双引擎。通过客户端转换bytecode字节码。使用jsc加载优化之前的纯文本js,一旦优化完毕切换至Hermes引擎。
  • 另外如果使用Hermes引擎我们需要充分测试稳定性和兼容性。
  • Hermes通过预编译字节码的方式提升js执行速度,给了我们新的思路。我们也正在调研JavaScriptCore或者V8的bytecode在移动端的支持度,性能和兼容性。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-08-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 携程技术中心 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
RN沙龙 | 携程是如何做React Native优化的
赵辛贵,携程无线开发高级技术经理,目前主要负责React Native框架在携程内部的使用推广和性能优化 React Native(下文简称RN)开源已经一年多时间,国内各大互联网公司都在使用,携程
携程技术
2018/03/16
3.9K0
RN沙龙 | 携程是如何做React Native优化的
JS引擎(1):JS引擎擂台赛,JavaScript引擎的特征比较及术语科普
上篇介绍过JavaScript引擎的历史,《JS引擎(0):起底各种JavaScript引擎群雄争霸之路》
周陆军博客
2023/04/09
9420
干货 | 终于来了!携程开源RN开发框架 - CRN
赵辛贵,携程无线平台研发部开发总监。2013年加入携程,主要负责App基础框架研发相关工作,曾参与Native、Hybrid和React Native框架设计、工程模块化、Android插件化等项目。目前重点关注React Native技术在公司的推广和研发支持、无线框架和工程架构升级。
携程技术
2019/04/22
2.8K0
干货 | 终于来了!携程开源RN开发框架 - CRN
如何不改一行代码,让Hippy启动速度提升50%?
目前QQ浏览器(下简称QB)使用Hippy的业务超过100个,基本上95%的核心业务都是使用Hippy作为首要技术栈来开发。但是跟Native相比较而言,Hippy是使用JS引擎进行异步渲染,在用户从点击到打开首屏可交互过程中会有一定的耗时,影响用户体验。如何优化这段耗时,尽量对齐Native体验,想必是每个团队需要思考优化的事情。
腾讯TMF团队
2022/12/15
1.5K0
重学JS-1.3-知识点:V8引擎
V8是一个由Google开发的开源JavaScript引擎,用于Chrome、Node.js等环境中,作用是将JS代码编译为不同CPU(Intel, ARM以及MIPS等)对应的汇编代码。
luciozhang
2023/04/22
7140
重学JS-1.3-知识点:V8引擎
逆袭Flutter? Facebook 发布全新跨平台引擎 Hermes!
移动应用变得愈加繁重的同时也愈加复杂了。开发者为应用添加新功能时通常会遇到卡顿等性能问题。虽然出现性能问题的原因是多种多样的,但用户不关心这些,他们只希望自己在任何设备上使用应用时都能有流畅的体验。
Android技术干货分享
2019/07/18
2K0
逆袭Flutter? Facebook 发布全新跨平台引擎 Hermes!
React Native 启动速度优化——JS 篇(全网最全,值得收藏)
上一篇文章主要从 Native 的角度分析了 React Native 的初始化流程,并从源码出发,总结了几个 React Native 容器初始化的优化点。本文主要从 JavaScript 入手,总结了一些 JS 侧的优化要点。
卤代烃
2021/04/26
2.6K0
React Native 启动速度优化——JS 篇(全网最全,值得收藏)
从Hybrid到React-Native: JS在移动端的南征北战史
其实写这篇文章的时候,我就知道,肯定有人问我:为什么不写flutter?抱歉了,flutter的大名我当然知道,可我只是一个写JS的,同时了解一些Java的知识,而flutter采用的编程语言,我暂时没有碰过,所以自然不敢妄加猜度,还请谅解
啦啦啦321
2019/09/29
3.3K0
深入理解JSCore
声明:本文是对美团技术团队唐笛《深入理解JSCore》一文的学习笔记,如要查看原文,请点击文末的“阅读原文”。
拉维
2019/08/12
2.4K0
深入理解JSCore
D8调试工具——jsvu的使用细则
执行 jsvu安装引擎,可在 %USERPROFILE% /.jsvu 目录下查看安装的引擎
甜点cc
2022/09/26
9070
D8调试工具——jsvu的使用细则
分享一篇可视化的JS引擎执行流程
接触了前端这么久以来,你每天跟JS打交道,你肯定也和我一样认为JavaScript很酷。但机器怎么能真正理解你写的代码呢?
程序员海军
2021/10/11
1.8K0
分享一篇可视化的JS引擎执行流程
V8、JSCore、Hermes、QuickJS,hybrid开发JS引擎怎么选
在一般的移动端开发场景中,每次更新应用功能都是通过 Native 语言开发并通过应用市场版本分发来实现的。
公众号@魔术师卡颂
2021/03/15
20.4K1
V8 Ignition:JS 引擎与字节码的不解之缘(转载)
首先贴个Javascript性能测试站点,测试并展示了数个 JavaScript 引擎的性能数据:arewefastyet
Clearlove
2019/08/29
1.2K0
V8 Ignition:JS 引擎与字节码的不解之缘(转载)
JS引擎(0):JavaScript引擎群雄演义—起底JavaScript引擎
JavaScript 既是一个 面向过程的语言 又是一个 面向对象的语言。在 JavaScript 中,通过在运行时给空对象附加方法和属性来创建对象,与编译语言如 C++ 和 Java 中常见的通过语法来定义类相反。对象构造后,它可以用作是创建相似对象的原型。
周陆军博客
2023/04/09
2.1K0
深入理解 JavaScript 引擎
食堂老板:这块的知识不仅面试可能会问,学会了 JS 引擎的工作原理,可以更好的理解 JavaScript、更好的理解前端生态中 Babel 的词法分析和语法分析,ESLint 的语法检查原理以及 React、Vue 等前端框架的实现原理。总之,学习引擎原理可谓是一举多得。
ConardLi
2021/09/29
1K0
深入理解 JavaScript 引擎
iOS引入JavaScriptCore引擎框架(一)
JavaScriptCore引擎     我们都知道WebKit是个渲染引擎,简单来说负责页面的布局,绘制以及层的合成,但是WebKit工程中不仅仅有关于渲染相关的逻辑,也集成了默认的javascript引擎--JavaScriptCore,目前Safari的js引擎也基于JSC构建,不过有一些私有的优化,总体性能相差不大。JSC的执行理念比较符合传统的引擎逻辑,它包括了2部分:解释器和简单方法JIT。解释器比较容易理解,针对某种类型的文件解释执行,在JSC中,它的目标文件是由代码构建的语法树生成的字节码文
欲休
2018/03/15
1.6K0
判断js引擎是javascriptCore或者v8
来由   纯粹的无聊,一直在搜索JavaScriptCore和SpiderMonkey的一些信息,却无意中学习了如何在ios的UIWebView中判断其js解析引擎的方法: if (window.devicePixelRatio) { //If WebKit browser var st = escape(navigator.javaEnabled.toString()); if (st === 'function%20javaEnabled%28%29%20%7B%20%5Bnative%
欲休
2018/03/15
3.5K0
浅谈移动端开发技术
之前上家公司主要是做移动端 H5 开发的,但相关技术和配套体系已经很成熟了,很难接触到背后的这套体系。
尹光耀
2022/03/22
2.3K0
浅谈移动端开发技术
干货 | 近万字长文详述携程大规模应用RN的工程化实践
赵辛贵,携程无线平台研发部开发总监。2013年加入携程,主要负责App基础框架研发相关工作,目前重点关注React Native技术在公司的推广和研发支持、无线框架和工程架构升级。
携程技术
2019/04/22
1.8K0
干货 | 近万字长文详述携程大规模应用RN的工程化实践
最火移动端跨平台方案盘点:React Native、weex、Flutter
跨平台一直是老生常谈的话题,cordova、ionic、react-native、weex、kotlin-native、flutter等跨平台框架的百花齐放,颇有一股推倒原生开发者的势头。
JackJiang
2018/08/13
7.4K0
最火移动端跨平台方案盘点:React Native、weex、Flutter
推荐阅读
相关推荐
RN沙龙 | 携程是如何做React Native优化的
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档