乐于分享
好东西不私藏

Hermes引擎开了,但App还是比Web慢,为什么?

Hermes引擎开了,但App还是比Web慢,为什么?

听说 Hermes 能大幅提升 React Native 的启动速度和运行性能,兴冲冲地开了。结果 App 启动还是慢,列表滚动还是卡。说好的"性能提升"呢?

先搞清楚:Hermes 到底做了什么

Hermes 是 Meta 为 React Native 开发的 JavaScript 引擎,替代了原来的 JSC(JavaScriptCore)。它的核心优化:

优化项
JSC
Hermes
启动方式
运行时解析 JS → 编译字节码
预编译字节码
(AOT)
内存占用
高(运行时编译)
低(直接执行字节码)
首屏时间
慢(需要先编译)
快(直接执行)
GC 策略
传统分代 GC
增量式 GC
(减少卡顿)

重点:Hermes 优化的是启动速度内存占用,不是"让所有东西都变快"。如果你的瓶颈不在启动,开了 Hermes 也不会有明显改善。

App 为什么还是慢

原因 1:瓶颈不在 JS 引擎

Hermes 优化的是 JS 执行速度。但大多数 React Native App 的性能瓶颈在:

  • Bridge 通信:JS 线程和 UI 线程之间的数据传输
  • 原生渲染:View 的创建、布局、绘制
  • 图片加载:网络图片的下载和解码
  • 动画性能:主线程阻塞

这些问题,换什么 JS 引擎都解决不了。

原因 2:没有用 Hermes 的专属优化

Hermes 支持一些 JSC 不支持的特性,如果你没用上,就白白浪费了:

✅ useTransition / useDeferredValue(React 18+)

Hermes 对 React 18 的并发特性有更好的支持:

import { useTransition, useState } from 'react';function SearchScreen() {  const [query, setQuery] = useState('');  const [results, setResults] = useState([]);  const [isPending, startTransition] = useTransition();  const handleSearch = (text: string) => {    setQuery(text);    // 低优先级更新,不阻塞输入    startTransition(() => {      setResults(filterResults(text));    });  };  return (    <View>      <TextInputvalue={query}onChangeText={handleSearch} />      {isPending ? <ActivityIndicator /> : <ResultListdata={results} />}    </View>  );}

✅ React.memo + useMemo + useCallback

Hermes 执行这些优化的速度更快,但你得先用上:

import React, { useMemo, useCallback } from 'react';// ✅ 避免不必要的重渲染const ListItem = React.memo(({ item, onPress }: Props) => {  return (    <TouchableOpacityonPress={() => onPress(item.id)}>      <Text>{item.title}</Text>    </TouchableOpacity>  );});// ✅ 缓存计算结果function ExpensiveComponent({ data }: { data: number[] }) {  const sorted = useMemo(() => [...data].sort((a, b) => a - b), [data]);  const total = useMemo(() => sorted.reduce((a, b) => a + b, 0), [sorted]);  return <Text>总计: {total}</Text>;}// ✅ 缓存回调函数function Parent() {  const handlePress = useCallback((id: string) => {    console.log('Pressed:', id);  }, []);  return <ListItemitem={item}onPress={handlePress} />;}

原因 3:图片没有优化

图片是 React Native App 最大的性能杀手之一。原图不解码、不缓存,直接显示:

// ❌ 没有尺寸限制,直接显示原图<Image source={{ uri'https://example.com/photo.jpg' }} />// ✅ 指定尺寸 + 使用 FastImageimport FastImage from 'react-native-fast-image';<FastImage  source={{     uri: 'https://example.com/photo.jpg',    priority: FastImage.priority.normal,  }}  style={{ width: 200height: 200 }}  resizeMode={FastImage.resizeMode.cover}/>

原因 4:列表没有虚拟化

渲染 1000 个列表项,即使 Hermes 再快也扛不住:

// ❌ 一次性渲染所有项<ScrollView>  {items.map(item => <Itemkey={item.id}data={item} />)}</ScrollView>// ✅ 用 FlatList,只渲染可见区域<FlatList  data={items}  renderItem={({ item }) => <Itemdata={item} />}  keyExtractor={(item) => item.id}  windowSize={5}          // 可视区域外保留的屏幕数  maxToRenderPerBatch={10} // 每批渲染的数量  removeClippedSubviews={true} // 移除屏幕外的视图/>

原因 5:Hermes 的 GC 没有被正确配置

Hermes 的增量式 GC 在某些场景下可能不如预期:

// 在 android/gradle.properties 中hermesEnabled=true// 如果遇到内存问题,可以调整 GC// 在 app.json (Expo) 或原生配置中{  "expo": {    "jsEngine""hermes",    "android": {      "jsEngine""hermes"    },    "ios": {      "jsEngine""hermes"    }  }}

真正的性能优化清单

第一层:基础(必须做)

  • 确认 Hermes 已开启
  • 生产包开启了 ProGuard(Android)
  • 图片指定了尺寸,用了 FastImage 或 expo-image
  • 列表用 FlatList,不用 ScrollView + map
  • 移除了 console.log(生产包)

第二层:进阶(推荐做)

  • 用 React.memo 包裹列表项组件
  • 用 useMemo 缓存计算结果
  • 用 useCallback 缓存回调函数
  • 图片用 WebP 格式(比 PNG 小 30%)
  •  启用 RAM bundles(按需加载模块)

第三层:高阶(性能敏感场景)

  • 用 Reanimated 做动画(UI 线程执行)
  • 用 InteractionManager 延迟非关键任务
  • 用 requestIdleCallback 做低优先级工作
  • 拆分大 Bundle,用 Code Splitting
  • 用 Flipper 的 Performance 面板找瓶颈

总结

误区
现实
开了 Hermes 就快了
只优化启动速度,不优化运行性能
JS 引擎是瓶颈
大部分瓶颈在 Bridge、渲染、图片
换引擎就够了
需要配合代码优化

Hermes 是地基,不是装修。地基打好了,房子还是要自己盖。