在 Hermes 成为 React Native 默认 JS 引擎的路上

在 Hermes 成为 React Native 默认 JS 引擎的路上
最新回答
云起兮衣飞扬

2022-12-16 03:45:06

Hermes 正在逐步推进成为 React Native 在所有平台上的默认 JavaScript 引擎,以下从优化举措、生态带动两方面介绍其发展情况:

优化举措
  • 为 React Native 优化

    核心特性:Hermes 的核心特性是提前编译(ahead-of-time),React Native 应用启用后携带预编译优化字节码,减少用户启动产品工作量。Facebook 及社区应用测量数据显示,启用 Hermes 能将近减少一半产品的 TTI(可交互时间)指标。

    为 Fabric 构建全新 GC

    GenGC 的缺陷:之前 Hermes 默认垃圾回收器是 GenGC,单线程分代式,新生代用半区复制策略,老生代用标记整理策略,虽擅返还未使用内存给操作系统,但单线程导致长时间 GC 暂停,复杂应用如安卓版 Facebook 平均暂停 200ms,p99 约 1.4s,甚至达 7s。

    Hades 的优势:实现全新高并发 GC 名为 Hades,回收新生代方式与 GenGC 一致,管理老生代用原始快照式标记擦除回收器,在后台线程执行大部分工作,不阻塞引擎主线程。64 位设备上 p99.9 暂停时间仅 48ms(比 GenGC 快 34 倍),32 位上 p99.9 约 88ms(作为单线程增量 CG 运行)。虽以整体吞吐量为代价,但通过合并等内存优化机制达更低整体内存占用。

    攻克性能痛点

    启动性能:在 Metro 中试验为 Hermes 提供专用 Babel 转换配置文件,用 Hermes 原生 ESNext 实现替换十多个 Babel 转换。内部数据显示 TTI 提升 18 - 25%,整体字节码大小减少,开源环境预计有类似效果。

    内存占用

    32 位编码优化:引入全新 32 位编码,SMI 和指针编码为 29 位,其余 JS 数字装箱到堆中,使 JavaScript 堆大小整体减少约 30%。

    内存布局压榨:对 JavaScript 对象在堆中表示的不同种类 GC 管理单元头文件内存布局压榨,再减少近 15%内存占用。

    垂直整合先驱

    调试支持:遵循 Chrome DevTools 协议,支持用 Chrome 调试器调试设备上 JavaScript,比传统远程 JS 调试好,支持同步原生调用场景,保证运行时环境与真机一致,调试工具成为 Flipper 一部分提供一站式开发方案。

    对象分配优化:在 React Native 中配置 Hermes 时,将前 32MB 直接分配到老生代(pre - tenuring),避免触发 GC 暂停造成 TTI 延迟。

    JSI API 集成:新 React Native 架构基于 JSI 实现,Hermes 的 JSI API 集成实现由 JS 引擎团队维护,能提供正确且性能好的实现,经 Facebook 规模实战检验。

    并发原语优化:过去 React Native 中 Promise 基于非标准化 setImmediate API 实现 polyfill,现努力将 JS 引擎原生 Promise 和微任务通过 JSI 实现,在平台上引入 queueMicrotask,更好支持现代异步 JavaScript 代码。

带动整个生态
  • 开拓到新的平台

    iOS 平台:React Native 0.64 中,Callstack 牵头将 Hermes 引入 iOS 平台,编写系列文章并主持播客介绍实现过程。跑分结果显示,与 JSC 相比,Hermes 在 iOS 上为 Mattermost 稳定提供近 40%启动优化,减少近 18%内存占用,应用程序增加 2.4MiB 开销。

    Windows 和 macOS 平台:微软推进将 Hermes 引入 React Native for Windows 和 React Native for macOS,在微软 Build 2020 大会上分享 Hermes 内存占用比 React Native for Windows 中的 Chakra 引擎低 13%。最近测试跑分发现,使用 Hades GC 并包含相关优化的 Hermes v0.8 版本,内存占用比其他引擎少近 30 - 40%。Messenger 桌面端应用视频通话体验跑在 Hermes 上。

    虚拟现实体验:所有 Oculus 上基于 React 技术构建的虚拟现实体验,包括 Oculus Home,由 Hermes 驱动。

  • 支持社区

    实现社区需求功能

    Proxy 实现:Proxy 和 Reflect 最初未被 Hermes 实现,因 Facebook 不使用且担心损害属性查询性能。但 MobX 和 Immer 等库流行使 Proxy 成为呼声最高功能,经评估后实现,找到对性能代价极小的方式,v4.0 和 v0.5 中提供可选 Proxy 支持的 npm 包,v0.7 起默认启用 Proxy。

    Intl 实现:ECMAScript 国际化 API 规范是呼声第二高的功能,Intl 是一组庞大 API,通常需实现包含 6MB 大小 Unicode CLDR 数据。为避免大幅增加 Hermes 二进制大小,通过直接访问与映射操作系统中所提供的 ICU 库的方式实现。Android 端支持由微软合作完成,对体积影响仅 3%(每个 ABI 约 57 - 62K),v0.8 中默认支持。Facebook 赞助项目,学生将添加 Hermes 在 iOS 上的 Intl 支持。

    解决社区问题

    修复与规范不符行为:修复 ES2019 中添加的 Array.prototype.sort 要求使用稳定排序的修订问题,将在下个版本发布。

    调整默认堆大小:将默认堆大小从 512MiB 提升至 3GiB,解决堆默认大小限制过小造成的不必要 GC 压力和内存溢出崩溃问题。

    改进 Function.prototype.toString 实现:改进特殊 Function.prototype.toString 实现,解决导致使用不恰当功能检测的库性能下降和无法做到源码注入问题,确定 Hermes 应尽可能不妨碍开发者工作,支持事实标准和实践。

综上所述,Hermes 已经做好成为所有 React Native 平台默认 JavaScript 引擎的准备,鼓励大家试用并根据情况在 GitHub 仓库提交 issue 反馈。