跳至主内容

Marketplace 中的 React Native 性能优化

· 1 分钟阅读
Facebook 软件工程师
非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

React Native 在 Facebook 生态的多个应用中均有使用,包括主应用中的顶层标签页。本文重点讨论高曝光产品 Marketplace。该服务已在十余个国家上线,让用户能发现其他用户提供的商品和服务。

2017 年上半年,通过 Relay 团队、Marketplace 团队、移动 JS 平台团队和 React Native 团队的协作,我们将 Android 2010-11 年款设备上的 Marketplace 交互就绪时间(TTI)缩短了一半。Facebook 历来将这些设备视为低端 Android 设备,它们在所有平台和设备类型中具有最长的 TTI。

典型的 React Native 启动流程如下所示:

免责声明:图示比例仅供参考,实际比例会因 React Native 的配置和使用方式而异。

我们首先初始化 React Native 核心(即 "Bridge"),然后运行产品特定的 JavaScript 代码,这些代码决定了 React Native 将在原生处理阶段渲染哪些视图。

另辟蹊径

我们早期的一个错误是过度依赖 Systrace 和 CTScan 来驱动性能优化。2016 年这些工具帮助我们发现了许多容易解决的问题,但我们后来认识到 Systrace 和 CTScan 无法代表生产环境场景,也不能模拟真实世界的情况。耗时分析的比例经常不准确,有时甚至完全偏离基准。极端情况下,某些预期仅需几毫秒的操作实际耗费了数百甚至数千毫秒。话虽如此,CTScan 仍有其价值——我们发现它能拦截三分之一的问题避免进入生产环境。

在 Android 平台上,我们将这些工具的局限性归因于:1) React Native 是多线程框架;2) Marketplace 与信息流等复杂视图共存;3) 计算时间波动极大。因此本阶段我们几乎完全依据生产环境测量数据和耗时分析来制定决策和优先级。

生产环境埋点实践

生产环境埋点看似简单,实则相当复杂。每个迭代周期需 2-3 周,涉及代码提交到主干、应用上架 Play 商店、收集足够生产环境样本以验证结果等多个高延迟环节。每个周期都需要验证:埋点数据是否准确、粒度是否合适、分项耗时能否正确累加为总耗时。我们无法依赖 alpha/beta 版本,因为它们不能代表真实用户群体。本质上,我们通过数百万样本的聚合数据,极其细致地构建了精确的生产环境追踪体系。

我们严格验证每毫秒分项数据能否正确累加到上级指标,原因之一是最初就发现埋点存在缺口。实际上,初始的耗时分析未计入线程切换导致的阻塞。线程切换本身开销不大,但切换到繁忙的工作线程代价极高。我们最终通过在关键位置插入 Thread.sleep() 在本地复现了这些阻塞,并通过以下方法解决:

  1. 消除对 AsyncTask 的依赖

  2. 取消在 UI 线程强制初始化 ReactContext 和 NativeModules

  3. 移除初始化阶段测量 ReactRootView 的依赖

通过共同解决这些线程阻塞问题,启动时间减少了超过 25%。

生产环境指标也挑战了我们之前的一些假设。例如,我们曾假设在启动路径上预加载 JavaScript 模块能降低初始化成本,因此将多个模块集中打包。然而实际证明,预加载和集中这些模块的成本远超收益。通过重新配置内联请求黑名单并从启动路径移除 JavaScript 模块,我们成功避免了加载非必要模块(例如在只需使用 Relay Modern 时加载了 Relay Classic)。如今我们的 RUN_JS_BUNDLE 分解指标速度提升了 75% 以上。

我们还通过优化特定产品的原生模块获得了性能提升。例如通过延迟注入某个原生模块的依赖项,将其成本降低了 98%。通过消除 Marketplace 启动与其他产品之间的资源争用,启动时间获得了同等幅度的缩减。

最值得称道的是,这些改进中有许多可广泛应用于所有基于 React Native 构建的界面。

结语

人们通常认为 React Native 的启动性能问题源于 JavaScript 运行缓慢或网络延迟过高。虽然提升 JavaScript 执行速度确实能显著降低 TTI(交互时间),但这些因素的实际影响比例远低于先前的预想。

当前获得的经验是:测量、测量、再测量!部分优化成果来自将运行时成本转移到构建阶段,例如 Relay Modern 和 Lazy NativeModules;部分成果来自通过更智能的代码并行化或删除无用代码来避免工作负载;还有部分成果则来自 React Native 的重大架构调整(如清理线程阻塞)。性能优化没有万能方案,长期成效将源自持续的检测与改进。切勿让认知偏差左右决策,而应通过严谨收集和解读生产环境数据来指导后续工作。

未来计划

长期目标是让 Marketplace 的 TTI 达到与原生构建的同类产品相当的水平,并实现 React Native 整体性能与原生方案持平。尽管过去半年我们将 React Native 桥接的启动成本降低了约 80%,但我们将通过 Prepack 等项目及更多构建时处理技术,最终将桥接成本降至趋近于零。