optimising-expo-react-native-performance

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Summary

概述

This skill turns “the app feels slow/janky” into a measured, repeatable, and shippable optimisation program for Expo-managed React Native apps.
Non‑negotiables:
  • Optimise against user-visible KPIs (startup/TTI, scroll FPS, navigation responsiveness, memory growth, p95 network latency).
  • Profile in production-like builds (release / profile / debugOptimized) — not in dev mode.
  • Make one change at a time, re-measure, and keep a rollback path.
本技能将“应用感觉卡顿/迟缓”转化为一套针对Expo托管式React Native应用的可量化可重复可交付的优化方案。
核心准则:
  • 针对用户可见的KPI进行优化(启动/首次交互时间、滚动帧率、导航响应速度、内存增长、95分位网络延迟)。
  • 类生产环境构建版本(release / profile / debugOptimized)中进行性能分析——禁止在开发模式下分析。
  • 每次仅做一项修改,重新测量,并保留回滚路径。

When to use

使用场景

Use when you need to:
  • Fix slow startup, “white screen”, or delayed time-to-interactive.
  • Fix scroll jank, dropped frames, sluggish taps, or slow transitions.
  • Reduce memory growth, crashes under pressure, or image/video bloat.
  • Reduce OTA update size, JS bundle size, or Android binary size.
  • Add regression prevention: perf budgets + CI gates + production monitoring.
适用于以下需求:
  • 修复启动缓慢、“白屏”或首次交互延迟问题。
  • 修复滚动卡顿、丢帧、点击迟缓或过渡动画缓慢问题。
  • 降低内存增长、压力下崩溃或图片/视频体积过大问题。
  • 减小OTA更新包大小、JS bundle体积或Android安装包大小。
  • 添加退化预防机制:性能预算 + CI门禁 + 生产环境监控。

When NOT to use

不适用场景

Don’t use this skill to:
  • Prematurely micro-optimise already-smooth screens with no KPI regression.
  • Make changes without a reproducible scenario and a baseline.
  • “Optimise” by switching libraries blindly (measure first).
请勿在以下场景使用本技能:
  • 对已流畅运行且无KPI退化的页面进行过早微优化。
  • 在无可复现场景和基准数据的情况下修改代码。
  • 盲目切换库来“优化”(先测量再行动)。

Inputs

输入信息

  • Repo (Expo managed or CNG/prebuild), ideally with:
    • package.json
    • app.json
      /
      app.config.*
    • metro.config.js
      (if present)
    • babel.config.*
    • eas.json
      (if using EAS)
  • A concrete report of the problem:
    • Device(s), OS versions, and which flow feels slow.
    • Steps to reproduce (or a screen name if using Expo Router).
If details are missing, infer as much as possible from the repo and propose a minimal repro script.
  • 代码仓库(Expo托管或CNG/prebuild),理想情况下包含:
    • package.json
    • app.json
      /
      app.config.*
    • metro.config.js
      (若存在)
    • babel.config.*
    • eas.json
      (若使用EAS)
  • 具体的问题报告:
    • 涉及的设备、操作系统版本,以及哪个流程感觉迟缓。
    • 复现步骤(若使用Expo Router则提供页面名称)。
若信息缺失,尽可能从仓库中推断,并提出最小化复现脚本。

Outputs

输出结果

Deliver both:
  1. Perf audit report (see template in
    assets/templates/perf-audit-report-template.md
    ):
    • KPIs + budgets
    • Baseline measurements (device + build type)
    • Root cause hypothesis + evidence
    • Fix plan (ordered by ROI / risk)
    • Before/after measurements
  2. Code changes (PR-ready) implementing the top fixes, plus:
    • Updated perf budgets (if needed)
    • CI gate(s) for bundle/update size at minimum
需同时交付:
  1. 性能审计报告(参考
    assets/templates/perf-audit-report-template.md
    中的模板):
    • KPI + 预算指标
    • 基准测量数据(设备 + 构建类型)
    • 根因假设 + 证据
    • 修复计划(按投资回报率/风险排序)
    • 优化前后的测量对比
  2. 代码变更(可直接提交PR):实现优先级最高的修复,同时包含:
    • 更新后的性能预算(若需要)
    • 至少针对bundle/更新包大小的CI门禁

Tooling assumptions

工具假设

You can use:
  • Expo CLI (
    npx expo …
    ), EAS CLI (
    eas …
    ) where available.
  • React Native DevTools (Performance + Memory panels) for JS-level analysis.
  • Native profilers (Android Studio, Xcode Instruments) for CPU/memory/UI tracing.
You should prefer:
  • Release/profile builds for measurement.
  • Same device class and same scenario script for before/after.
可使用以下工具:
  • Expo CLI (
    npx expo …
    )、EAS CLI (
    eas …
    )(若可用)。
  • React Native DevTools(Performance + Memory面板)用于JS层面分析。
  • 原生性能分析工具(Android Studio、Xcode Instruments)用于CPU/内存/UI追踪。
优先选择:
  • Release/profile构建版本进行测量。
  • 优化前后使用同一设备类别同一场景脚本

The optimisation workflow (high level)

优化工作流(概览)

  1. Define KPIs + budgets (3–6 metrics max). Pick what users feel.
  2. Create a repeatable scenario (startup, list scroll, key navigation, etc.).
  3. Measure baseline in a production-like build.
  4. Classify the bottleneck domain:
    • Startup/bundle
    • JS thread
    • UI thread
    • Lists/images
    • Memory
    • Network/background
  5. Apply targeted fixes (smallest change, highest ROI first).
  6. Re-measure. Keep only changes with KPI wins.
  7. Add regression control (budgets + CI gates + monitoring).
  1. 定义KPI + 预算(最多3–6个指标)。选择用户能感知的指标。
  2. 创建可重复的测试场景(启动、列表滚动、关键导航等)。
  3. 在类生产构建版本中测量基准数据
  4. 分类瓶颈领域
    • 启动/bundle
    • JS线程
    • UI线程
    • 列表/图片
    • 内存
    • 网络/后台任务
  5. 应用定向修复(优先选择改动最小、投资回报率最高的方案)。
  6. 重新测量。仅保留能带来KPI提升的修改。
  7. 添加退化管控机制(预算 + CI门禁 + 监控)。

Detailed playbook

详细操作手册

Phase 0 — Establish reality (no guesswork)

阶段0 — 明确现状(拒绝猜测)

0.1 Identify versions and architecture
  • Expo SDK version, React Native version, React version.
  • New Architecture status (mandatory in newer SDKs).
  • JS engine (Hermes/JSC/V8), OTA updates usage (
    expo-updates
    ).
  • Major perf-sensitive libs: navigation (Expo Router/React Navigation), lists (FlashList), animation (Reanimated), images (
    expo-image
    ).
0.2 Choose KPIs (pick 3–6) Suggested defaults:
  • Cold start: time-to-first-render and/or time-to-interactive
  • Scroll: dropped frames / FPS on the heaviest list
  • Navigation: p95 screen transition time for a representative flow
  • Memory: steady-state RSS after repeating a navigation loop 5–10×
  • Network: p95 API latency on a key endpoint
Record budgets as numbers (not “fast”). See
references/00-principles-and-kpis.md
.
0.3 Choose build type for measuring
  • Prefer store-equivalent Release.
  • If you need debuggability, use Android “profileable” builds, iOS Instruments, or Expo’s
    debugOptimized
    where applicable.
0.1 确认版本与架构
  • Expo SDK版本、React Native版本、React版本。
  • New Architecture状态(新版本SDK中为必填)。
  • JS引擎(Hermes/JSC/V8)、OTA更新使用情况(
    expo-updates
    )。
  • 主要性能敏感库:导航(Expo Router/React Navigation)、列表(FlashList)、动画(Reanimated)、图片(
    expo-image
    )。
0.2 选择KPI(选3–6个) 建议默认指标:
  • 冷启动:首次渲染时间和/或首次交互时间
  • 滚动:最重列表的丢帧率 / FPS
  • 导航:代表性流程的95分位页面过渡时间
  • 内存:重复导航循环5–10次后的稳态RSS
  • 网络:关键接口的95分位延迟
将预算记录为具体数值(而非“快”)。参考
references/00-principles-and-kpis.md
0.3 选择用于测量的构建类型
  • 优先选择与应用商店版本一致的Release版本。
  • 若需要可调试性,使用Android“profileable”构建版本、iOS Instruments,或适用的Expo
    debugOptimized
    版本。

Phase 1 — Baseline measurement (release-build discipline)

阶段1 — 基准测量(严格遵循发布版本规范)

1.1 Baseline checklist (must pass)
  • Dev mode off.
  • No remote JS debugging.
  • Same device, same OS version, same network conditions.
  • Warm vs cold start explicitly noted.
1.2 Capture traces and numbers
  • React Native DevTools:
    • Performance trace (JS execution + React tracks + network events)
    • Heap snapshot (if memory suspected)
  • Native tools:
    • Android Studio System Trace for jank attribution
    • Xcode Instruments (Time Profiler / Allocations / Leaks)
Store raw artefacts (trace files, screenshots) alongside your report.
1.1 基准检查清单(必须满足)
  • 关闭开发模式。
  • 禁用远程JS调试。
  • 使用同一设备、同一操作系统版本、同一网络环境。
  • 明确标注是热启动还是冷启动。
1.2 捕获追踪数据与数值
  • React Native DevTools:
    • 性能追踪(JS执行 + React追踪 + 网络事件)
    • 堆快照(若怀疑内存问题)
  • 原生工具:
    • Android Studio System Trace用于卡顿归因
    • Xcode Instruments(Time Profiler / Allocations / Leaks)
将原始产物(追踪文件、截图)与报告一起存储。

Phase 2 — Decide the bottleneck domain

阶段2 — 判断瓶颈领域

Use this decision rubric:
  • Startup slow: long splash, white screen, slow first render → startup/bundle.
  • Taps lag / transitions slow but scrolling OK → JS thread or navigation.
  • Scroll stutters even with little JS work → UI thread or list/render cost.
  • Memory climbs over time → leak / image/video pressure.
  • Everything waits on API → network/caching.
使用以下判定规则:
  • 启动缓慢:启动页时长过长、白屏、首次渲染延迟 → 启动/bundle领域。
  • 点击延迟 / 过渡缓慢但滚动正常 → JS线程或导航领域。
  • 滚动卡顿且JS任务量小 → UI线程或列表/渲染成本领域。
  • 内存持续增长 → 内存泄漏 / 图片/视频压力领域。
  • 所有操作等待API响应 → 网络/缓存领域。

Phase 3 — Apply high-ROI fixes by domain

阶段3 — 按领域应用高投资回报率修复方案

A) Startup & bundle

A) 启动与bundle

Do in this order:
  1. Stop doing work before first paint
    • Gate only critical assets (fonts, tiny config) and hide splash ASAP.
  2. Confirm Hermes
    • Make it explicit in app config if necessary.
    • If you use OTA updates, ensure runtime compatibility when engine/bytecode changes.
  3. Shrink JS evaluation
    • Prefer ESM imports, avoid breaking tree shaking.
    • Consider Metro
      inlineRequires
      (validate side effects!).
  4. Control OTA payloads
    • Configure update asset inclusion/exclusion and verify assets.
  5. Android size knobs (measure trade-offs)
    • Enable R8 minify + resource shrinking.
    • Treat bundle compression as a measured toggle (smaller APK vs slower startup).
See
references/02-startup-bundle-ota.md
.
按以下顺序操作:
  1. 停止首次绘制前的非必要工作
    • 仅加载关键资源(字体、小型配置)并尽快隐藏启动页。
  2. 确认启用Hermes
    • 必要时在应用配置中明确声明。
    • 若使用OTA更新,确保引擎/字节码变更时的运行时兼容性。
  3. 减少JS解析时间
    • 优先使用ESM导入,避免破坏tree shaking。
    • 考虑启用Metro
      inlineRequires
      (需验证副作用!)。
  4. 管控OTA payload大小
    • 配置更新资源的包含/排除规则并验证资源。
  5. Android体积优化选项(权衡测量)
    • 启用R8混淆 + 资源压缩。
    • 将bundle压缩视为可测量的开关(更小APK vs 更慢启动)。
参考
references/02-startup-bundle-ota.md

B) JS thread stalls (renders + computation)

B) JS线程阻塞(渲染 + 计算)

High ROI:
  1. Remove production
    console.*
    .
  2. Defer heavy work with
    InteractionManager
    /
    requestAnimationFrame
    .
  3. Reduce re-renders:
    • Stabilise props, split context, memoise hot rows.
    • Consider React Compiler (branch rollout + profiling + easy rollback).
See
references/03-rendering-js-ui.md
.
高投资回报率方案:
  1. 移除生产环境中的
    console.*
    语句。
  2. 使用
    InteractionManager
    /
    requestAnimationFrame
    延迟繁重任务。
  3. 减少重渲染:
    • 稳定props、拆分context、缓存高频行组件。
    • 考虑使用React Compiler(分阶段发布 + 性能分析 + 易回滚)。
参考
references/03-rendering-js-ui.md

C) UI thread / rendering / animations

C) UI线程 / 渲染 / 动画

High ROI:
  1. Prefer native-driven transitions (native stack /
    react-native-screens
    ).
  2. Avoid expensive UI operations on animated frames:
    • Alpha compositing, heavy shadows, animating image size.
  3. Use native-driver animations where possible; for complex gestures prefer Reanimated worklets.
See
references/03-rendering-js-ui.md
.
高投资回报率方案:
  1. 优先使用原生驱动的过渡效果(native stack /
    react-native-screens
    )。
  2. 避免在动画帧上执行昂贵UI操作:
    • Alpha合成、复杂阴影、图片尺寸动画。
  3. 尽可能使用原生驱动动画;复杂手势优先使用Reanimated worklets。
参考
references/03-rendering-js-ui.md

D) Lists, images, and media

D) 列表、图片与媒体

High ROI:
  1. Fix list fundamentals:
    • Stable keys, avoid re-render storms, tune render window.
    • Add
      getItemLayout
      when item heights are known.
  2. If still janky: evaluate FlashList for large/complex feeds.
  3. Move image-heavy UIs to
    expo-image
    with caching + placeholders.
  4. For replay-heavy video: use
    expo-video
    caching with a storage policy.
See
references/04-lists-images-media.md
.
高投资回报率方案:
  1. 修复列表基础问题:
    • 使用稳定key、避免重渲染风暴、调整渲染窗口。
    • 若已知项高度,添加
      getItemLayout
  2. 若仍卡顿:针对大型/复杂信息流评估FlashList。
  3. 将图片密集型UI迁移到
    expo-image
    ,并启用缓存 + 占位符。
  4. 针对频繁回放的视频:使用
    expo-video
    缓存并配置存储策略。
参考
references/04-lists-images-media.md

E) Memory leaks / pressure

E) 内存泄漏 / 内存压力

High ROI:
  1. Reproduce with a navigation stress loop.
  2. Take JS heap snapshots (before/after) to spot retained graphs.
  3. If JS heap stable but RSS grows: switch to native allocation tools.
See
references/01-profiling-toolchain.md
.
高投资回报率方案:
  1. 通过导航压力循环复现问题。
  2. 生成JS堆快照(前后对比)以识别内存保留图。
  3. 若JS堆稳定但RSS增长:切换到原生分配工具分析。
参考
references/01-profiling-toolchain.md

F) Network & background work

F) 网络与后台任务

High ROI:
  1. Prevent refetch storms: cache + dedupe + prefetch.
  2. Use platform-appropriate background scheduling (best effort) for sync.
See
references/05-network-background.md
.
高投资回报率方案:
  1. 防止重复请求风暴:缓存 + 去重 + 预加载。
  2. 使用平台适配的后台调度机制(尽力而为)进行同步。
参考
references/05-network-background.md

Phase 4 — Regression control (the “next level”)

阶段4 — 退化管控(进阶环节)

Minimum viable regression control:
  • Budget file committed (bundle size + a few KPI thresholds).
  • CI gate that fails on obvious regressions (bundle/update size growth).
  • Production monitoring (crash + perf traces) with symbolication.
See
references/06-ci-regression.md
.
最小可行退化管控:
  • 提交预算文件(bundle大小 + 若干KPI阈值)。
  • 设置CI门禁,在出现明显退化(bundle/更新包体积增长)时触发失败。
  • 配置生产环境监控(崩溃 + 性能追踪)并启用符号化。
参考
references/06-ci-regression.md

Common pitfalls (things this skill forbids)

常见误区(本技能禁止的操作)

  • Benchmarking in dev mode and trusting the results.
  • Making 5 optimisations at once, then not knowing which mattered.
  • “Fixing” a symptom (e.g. bigger splash delay) instead of root cause (slow JS eval).
  • Turning on size flags (bundle compression, aggressive shrinking) without measuring startup and runtime.
  • 在开发模式下进行基准测试并信任结果。
  • 同时进行5项优化,却无法确定哪项起作用。
  • “修复”症状(如延长启动页时长)而非根因(JS解析缓慢)。
  • 未测量启动和运行时影响就启用体积优化开关(bundle压缩、激进压缩)。

Fast checklist

快速检查清单

  • KPIs chosen (3–6) + budgets written down
  • Baseline measured in production-like build
  • Bottleneck domain identified with evidence
  • One fix at a time + before/after numbers
  • At least one regression gate added (bundle/update size)
  • Monitoring configured (crash + perf)
  • 已选择KPI(3–6个)并记录预算
  • 已在类生产构建版本中测量基准数据
  • 已凭证据确定瓶颈领域
  • 每次仅进行一项修复 + 记录优化前后数据
  • 已添加至少一项退化门禁(bundle/更新包大小)
  • 已配置监控(崩溃 + 性能)

References

参考资料

Start here:
  • references/00-principles-and-kpis.md
  • references/01-profiling-toolchain.md
  • references/02-startup-bundle-ota.md
  • references/03-rendering-js-ui.md
  • references/04-lists-images-media.md
  • references/06-ci-regression.md
External links: see
references/resources.md
.
从以下文件开始:
  • references/00-principles-and-kpis.md
  • references/01-profiling-toolchain.md
  • references/02-startup-bundle-ota.md
  • references/03-rendering-js-ui.md
  • references/04-lists-images-media.md
  • references/06-ci-regression.md
外部链接:参考
references/resources.md