RN(React Native)性能问题,基本可以归纳成三个核心方向:JS 卡顿、UI 卡顿、JS ↔ Native 桥接通信耗时。这三个问题经常互相影响,但排查思路并不一样。
1. JS 卡顿:JavaScript 线程忙不过来
RN 中大量业务逻辑运行在 JS Thread。如果 JS 线程长时间执行任务,就会出现:
- 点击后很久才响应
- 动画掉帧
- FlatList 滑动不流畅
- 手势响应延迟
setState后 UI 更新迟缓- 定时器、Promise 回调堆积
典型问题:
c
const result = hugeArray.map(item => {
// 大量计算
return heavyCalculate(item);
});
或者:
ini
JSON.parse(largeJson);
JSON.stringify(hugeObject);
以及:
css
for (let i = 0; i < 10000000; i++) {
// CPU 密集型任务
}
核心原则:不要让 JS Thread 长时间同步执行重计算。
常见优化:
重计算
↓
拆分任务
↓
减少计算量
↓
缓存结果
↓
避免无意义 render
↓
必要时交给 Native / JSI / Worklet
2. UI 卡顿:Native UI Thread 掉帧
UI 卡顿和 JS 卡顿不是一回事。
例如:
markdown
JS Thread 正常
↓
UI Thread 忙于布局 / 绘制
↓
FPS ↓
↓
用户看到掉帧
常见原因:
① 页面组件太多
例如一个页面同时渲染几百个 View。
② FlatList 使用不当
ini
<FlatList
data={data}
renderItem={renderItem}
/>
如果数据量很大,需要重点考虑:
ini
<FlatList
data={data}
initialNumToRender={10}
maxToRenderPerBatch={10}
windowSize={5}
removeClippedSubviews
/>
同时避免:
ini
renderItem={() => <ComplexComponent />}
每次 render 都创建大量对象、函数或者复杂组件。
③ 图片太大
比如:
yaml
原图 4000 × 3000
↓
RN 页面只显示 200 × 150
↓
仍然加载超大图片
↓
解码 + 内存 + GPU 压力
图片性能经常是移动端 UI 卡顿的隐藏杀手。
3. 桥接通信耗时:JS ↔ Native
这是 RN 早期架构中非常典型的问题。
传统架构可以简单理解成:
arduino
JavaScript
│
│ Bridge
↓
Native
│
↓
UI
如果 JS 和 Native 之间频繁传输大量数据:
arduino
JS
↓
Bridge
↓
Native
↓
Bridge
↓
JS
↓
Bridge
↓
Native
就容易产生明显开销。
例如:
ini
NativeModule.sendHugeData(largeObject);
如果 largeObject 非常大,而且调用频率很高,就可能造成性能问题。
尤其是这种模式:
scss
for (...) {
NativeModule.doSomething();
}
比:
ini
NativeModule.doBatchSomething(data);
更容易产生通信开销。
核心原则:减少 JS ↔ Native 通信次数,同时减少传输数据量。
4. 新架构:Bridge 不再是唯一核心
现在 RN 性能优化不能只盯着传统 Bridge。
React Native 新架构主要涉及:
JSI
Fabric
TurboModules
Hermes
可以简单理解:
arduino
旧架构
JS
│
Bridge
│
Native
而新架构更加倾向于:
JS
│
JSI
│
Native
因此一些过去严重依赖 Bridge 的性能问题,在新架构下会得到改善。
但这并不意味着:
"用了新架构,RN 就不会卡。"
实际上:
JS 重计算依然会卡。
Native UI 渲染压力依然会卡。
大量数据传递依然可能造成性能问题。
所以 RN 性能优化最终还是要回到:
markdown
JS 性能
+
React Render 性能
+
UI / Layout 性能
+
Native 性能
+
通信性能
+
内存
+
图片
5. 面试/实际项目可以这样建立排查思路
遇到:
"RN 页面很卡"
不要直接开始改代码,而是先判断到底是谁卡了:
markdown
页面卡顿
│
┌─────────┴─────────┐
↓ ↓
JS 卡顿 UI 卡顿
│ │
JS 是否长任务? Layout 是否复杂?
是否频繁 render? 图片是否过大?
是否大量计算? 列表是否优化?
│ │
└─────────┬─────────┘
↓
JS ↔ Native
是否频繁通信?
│
↓
内存 / 图片 / IO
一句话总结
| 问题 | 主要表现 | 优化方向 |
|---|---|---|
| JS 卡顿 | 点击延迟、动画不响应 | 减少 JS 重计算、减少 render |
| UI 卡顿 | 掉帧、滑动不流畅 | 优化布局、列表、图片、绘制 |
| 桥接耗时 | JS/Native 交互慢 | 减少通信次数和数据量 |
| 内存问题 | 页面越来越卡甚至崩溃 | 图片、缓存、组件生命周期 |
| React Render | 状态变化导致大量组件更新 | memo、拆组件、状态下沉 |
| 列表性能 | 长列表 FPS 下降 | FlatList/FlashList、虚拟化 |
| 新架构问题 | 某些 Native 模块性能异常 | JSI、TurboModule、Fabric |