HarmonyOS APP<玩转React>开源教程三十三:性能优化实战
很多结构性优化,其实从一开始就应该考虑。
第33次:性能优化实战
本文不做空泛理论,而是专门总结当前项目里已经出现的性能优化思路。虽然它不是一个超大应用,但在服务缓存、列表刷新、局部滚动、条件渲染等方面已经有不少值得学习的做法。
为什么这个项目也需要性能意识
很多人会觉得“数据不大、页面不多,就不用管性能”。其实并不是这样。移动端项目尤其是学习类应用,性能问题往往体现在这些细节里:
- 页面切换时卡顿
- 列表状态不同步
- 长内容滚动不顺畅
- 不必要的重复初始化
当前项目虽然规模不算大,但已经在多个位置体现了“先把基础性能做好”的意识。
一、服务缓存是这个项目最明显的优化点
最典型的例子有两个:
ProgressService.cachedProgressBookmarkService.cachedBookmarks
为什么这很重要?因为:
- 首页、模块详情、课时详情、个人中心都会读进度
- 模块详情、课时详情、收藏页都会读收藏状态
如果每次都异步去本地读取,不仅写法麻烦,还会增加刷新成本。服务层缓存的价值在于:
- 把高频读取变成同步读取
- 让页面判断状态更轻
- 降低重复 IO
这就是学习型应用里非常实用的一类优化。
二、统一初始化本身也是一种性能优化
Index.ets 会在启动时统一初始化:
- 存储
- 教程数据
- 搜索服务
- 徽章服务
- 收藏服务
这样做避免了多个子页面分别重复初始化同一套基础数据。对于当前项目来说,这种集中初始化比“每页自己准备数据”更稳,也更省资源。
这说明性能优化不一定都是低层技巧,很多时候它首先是一种结构设计能力。
三、列表刷新为什么要精准
项目中有一个很值得注意的小技巧,就是 ModuleDetail 里的 bookmarkVersion。它不是粗暴整页重载,而是通过更换 ForEach 的 key 来让列表项重新渲染。
这类“精准刷新”思路很重要,因为移动端最怕的就是:
- 明明只改了一项状态
- 却整页大面积重绘
当前项目虽然没有做很复杂的虚拟列表,但已经体现了“局部变化局部刷新”的意识,这一点非常值得保留。
四、长内容为什么都做了局部滚动
当前项目里很多容易变长的内容区都采用了局部滚动策略,例如:
CodeBlock代码区CodePlayground代码预览区- 源码详情页源码区
- 开源项目详情页完整示例区
并且常常会配合:
constraintSize({ maxHeight: ... })scrollBar(BarState.Auto/Off)
这样做的好处非常直接:
- 页面整体结构不会被一段长内容撑坏
- 只有真正需要滚动的区域才滚
- 用户阅读路径更稳定
这是一种既提升性能、也提升体验的写法。
五、Builder 拆分为什么也算性能优化
像 Index.ets 这种大页面,如果所有 UI 都堆在一个 build() 里,不仅难维护,状态变化时也更难判断哪些区域该更新。当前项目通过大量 @Builder 拆分:
HomeContentQuickAccessSectionRecommendedModulesSectionProfileContentBadgesSection
这首先是可维护性优化,但也间接有利于性能,因为页面结构更清晰,状态依赖关系也更容易控制。
换句话说,代码结构好,本身就是性能优化的前提。
六、当前项目还能优化哪些地方
既然这一篇叫“实战”,就不能只夸优点。结合当前源码和实际构建结果,还能继续优化的地方也很明确:
Index.ets体积较大,后续可以继续拆分子组件。- 一些页面仍然频繁使用过时 API,未来升级时要同步梳理导航性能和状态同步策略。
- 下载页、详情页中的大段文本和代码,如果未来数据量继续增大,可以进一步考虑懒加载或分段渲染。
- rawfile 中包含较多源码型资源,构建时已经出现 source code check 警告,后续发布前需要继续收敛打包体积和资源结构。
教程把这些讲出来,才是真正对项目负责。
七、自己检查性能时可以怎么做
- 打开首页,切换各个 Tab,观察是否有明显卡顿。
- 连续收藏和取消收藏,看列表刷新是否即时而且稳定。
- 打开长代码页面,测试局部滚动是否顺畅。
- 进入题库、错题本、源码详情页,观察页面初次加载节奏。
- 再结合构建输出,梳理哪些是“警告级风险”,哪些是“真实卡顿点”。
这样你会建立起更真实的性能判断能力,而不是只看空洞指标。
八、本篇常见坑
1. 把性能优化理解成最后再做
很多结构性优化,其实从一开始就应该考虑。
2. 只盯着算法,不看页面结构
页面拆分、服务缓存、滚动策略同样重要。
3. 发现刷新问题就整页重载
更好的办法往往是局部刷新和状态精确管理。
4. 忽略构建阶段的资源警告
这些警告常常和最终体积、加载效率有关。
本篇小结
当前项目里的性能优化不是靠某一个大招,而是靠一系列基础但有效的做法叠加出来的:
- 服务缓存
- 统一初始化
- 精准列表刷新
- 长内容局部滚动
- Builder 拆分
这正是中小型鸿蒙项目最实用的优化路线。
跟着真实源码继续往下看
进度缓存的真实代码如下:
export class ProgressService {
private static cachedProgress: UserProgress | null = null;
static getCachedProgress(): UserProgress {
return ProgressService.cachedProgress ?? DEFAULT_USER_PROGRESS;
}
}
收藏列表局部刷新的真实代码如下:
ForEach(this.module.lessons, (lesson: Lesson) => {
ListItem() {
LessonItem({ lesson: lesson })
}
}, (lesson: Lesson) => `${lesson.id}_${this.bookmarkVersion}`)
按这个顺序动手
- 打开
ProgressService.ets,确认缓存字段和同步读取方法。 - 再打开
ModuleDetail.ets,看bookmarkVersion怎么参与ForEachkey。 - 最后去几个长代码页确认局部滚动区域是否都做了高度限制。
课后练习
- 自己列出项目里三个“缓存换同步体验”的例子。
- 思考
Index.ets如果继续拆分,最先该拆哪个内容区,为什么。 - 对照当前构建输出,写下你认为最值得优先处理的一条性能或工程警告。
更多推荐


所有评论(0)