

子玥酱 (掘金 / 知乎 / CSDN / 简书 同名)
大家好,我是 子玥酱,一名长期深耕在一线的前端程序媛 👩💻。曾就职于多家知名互联网大厂,目前在某国企负责前端软件研发相关工作,主要聚焦于业务型系统的工程化建设与长期维护。
我持续输出和沉淀前端领域的实战经验,日常关注并分享的技术方向包括 前端工程化、小程序、React / RN、Flutter、跨端方案,
在复杂业务落地、组件抽象、性能优化以及多端协作方面积累了大量真实项目经验。
技术方向: 前端 / 跨端 / 小程序 / 移动端工程化 内容平台: 掘金、知乎、CSDN、简书 创作特点: 实战导向、源码拆解、少空谈多落地 **文章状态:**长期稳定更新,大量原创输出
我的内容主要围绕 前端技术实战、真实业务踩坑总结、框架与方案选型思考、行业趋势解读 展开。文章不会停留在"API 怎么用",而是更关注为什么这么设计、在什么场景下容易踩坑、真实项目中如何取舍,希望能帮你在实际工作中少走弯路。
子玥酱 · 前端成长记录官 ✨
👋 如果你正在做前端,或准备长期走前端这条路
📚 关注我,第一时间获取前端行业趋势与实践总结
🎁 可领取 11 类前端进阶学习资源 (工程化 / 框架 / 跨端 / 面试 / 架构)
💡 一起把技术学"明白",也用"到位"
持续写作,持续进阶。
愿我们都能在代码和生活里,走得更稳一点 🌱
文章目录
-
- 引言
- [一、最大的性能杀手:滥用 @State](#一、最大的性能杀手:滥用 @State)
- [二、ForEach Key 写错,性能直接腰斩](#二、ForEach Key 写错,性能直接腰斩)
- [三、不要在 build() 里面做计算](#三、不要在 build() 里面做计算)
- [四、同步 IO 才是真正的卡顿源头](#四、同步 IO 才是真正的卡顿源头)
- 五、组件层级过深,比复杂动画更危险
- 六、真正被忽略的是组件重建
- 七、最容易被忽略的图片问题
- [八、流畅度优化的本质,其实是 Runtime 优化](#八、流畅度优化的本质,其实是 Runtime 优化)
- 总结
-
- [1、 滥用 @State](#1、 滥用 @State)
- [2、 ForEach Key 错误](#2、 ForEach Key 错误)
- [3、 build() 中做复杂计算](#3、 build() 中做复杂计算)
- [4、 主线程同步 IO](#4、 主线程同步 IO)
- [5、 组件层级过深](#5、 组件层级过深)
引言
很多开发者做 HarmonyOS App 时,都会把精力放在:
text
ArkUI 组件
状态管理
动画效果
但上线以后,经常会遇到一个问题:
text
功能没问题
代码也没报错
为什么用户总觉得不够流畅?
甚至有些应用:
text
CPU占用不高
内存也正常
FPS测试也有60帧
但实际体验却总感觉:
text
卡顿
掉帧
点击延迟
页面切换不顺滑
很多人会下意识认为:
是系统问题。
其实恰恰相反。真正影响流畅度的,往往不是复杂算法,而是一些开发者最容易忽略的小细节。
而这些细节,在 HarmonyOS NEXT 的声明式 UI 和状态驱动架构下,会被进一步放大。
很多时候:
text
一个错误的 @State
一个不合理的组件层级
一次频繁重建
一次同步 IO
就足以毁掉整个页面体验。
今天我们从 Runtime 的角度,看一看:
HarmonyOS App 流畅度优化最容易被忽略的 5 个细节。
一、最大的性能杀手:滥用 @State
很多刚接触 ArkUI 的开发者都有一个习惯:
ts
@State list: Goods[] = []
@State userInfo: UserInfo = {}
@State orderInfo: Order = {}
@State messageList: Message[] = []
@State tabIndex: number = 0
恨不得所有数据都放进:
text
@State
但实际上:
text
@State = UI重绘触发器
意味着:
text
数据变化
↓
组件重新构建
↓
Diff Tree
↓
Render Tree
如果 State 太大:
text
一个字段变化
可能触发整个页面刷新
错误方式
ts
@State pageData: PageData
修改:
ts
this.pageData.user.name = "Tom"
可能导致:
text
整个页面重新 Build
而正确做法应该是:
拆分状态
ts
@State username: string = ""
@State avatar: string = ""
@State vipLevel: number = 0
让刷新粒度尽可能小,真正需要记住:
State 越大,重绘成本越高。
不是所有数据都应该放进 State。
二、ForEach Key 写错,性能直接腰斩
很多列表卡顿,问题不在 List,而在 Key。
错误写法
ts
ForEach(
this.goodsList,
(item,index)=>{
GoodsItem({
item:item
})
}
)
默认使用 index,看起来没问题。但是下面发生后:
text
插入数据
删除数据
排序变化
Framework 会认为:
text
所有节点都发生变化
于是:
text
全部重新创建
例如,1000 个商品,顶部插入一个数据:
text
理论上:
只新增1个组件
实际上:
1000个组件全部重建
正确方式:
ts
ForEach(
this.goodsList,
item=>{
GoodsItem({
item:item
})
},
item=>item.id
)
利用唯一 Key:
text
Diff成本大幅下降
这是很多开发者最容易忽略的问题,也是列表掉帧最常见原因。
三、不要在 build() 里面做计算
很多代码喜欢这样写:
ts
build() {
let totalPrice = this.goodsList.reduce(
(sum,item)=>sum+item.price,
0
)
Column() {
Text(totalPrice.toString())
}
}
问题在于:
text
build()
不是只执行一次,而是:
text
状态变化
↓
重新 Build
意味着,每一次刷新:
text
reduce()
filter()
sort()
map()
都会重新执行,如果列表:
text
1000条
频繁刷新,CPU 就会不断浪费在重复计算上。
正确方式,提前计算:
ts
@State totalPrice:number=0
updatePrice() {
this.totalPrice =
this.goodsList.reduce(
(sum,item)=>sum+item.price,
0
)
}
让:
text
build()
=
纯UI描述
而不是:
text
UI + 业务逻辑 + 数据计算
这是声明式 UI 的核心原则。
四、同步 IO 才是真正的卡顿源头
很多人优化半天:
text
动画
组件
布局
却忽略真正的大杀器:
text
同步操作
例如,页面初始化:
ts
aboutToAppear() {
let data = fs.readTextSync(path)
this.content = data
}
或者:
ts
JSON.parse(超大文件)
或者:
text
数据库查询
网络请求等待
图片解码
这些操作如果发生在主线程,结果就是:
text
UI线程阻塞
表现出来:
text
页面白屏
点击无响应
动画掉帧
正确方式:放入异步任务。例如:
ts
async aboutToAppear() {
let data =
await fs.readText(path)
this.content = data
}
或者:
text
TaskPool
Worker
进行后台处理,很多时候:
卡顿不是渲染慢,而是主线程被堵死。
五、组件层级过深,比复杂动画更危险
很多页面结构:
text
Column
├── Column
├── Column
├── Row
├── Stack
├── Column
几十层嵌套,看起来很优雅。
但实际上,布局阶段需要:
text
Measure
↓
Layout
↓
Draw
层级越深,计算越复杂。尤其:
text
List
+
复杂组件
+
Nested Column
+
大量 Stack
容易出现:
text
FPS下降
滑动卡顿
例如,错误结构:
text
Column
Column
Column
Row
Stack
Text
优化后:
text
Row
Text
层级减少以后:
text
Layout耗时下降
体验会明显提升,很多时候:
少一层布局,比优化动画更有效。
六、真正被忽略的是组件重建
很多开发者以为:
text
状态变化
=
属性更新
其实很多时候,状态变化导致的是:
text
组件销毁
↓
组件重建
例如:
ts
if (this.login) {
UserPage()
}
else {
LoginPage()
}
每次切换:
text
整个组件树重建
内部:
text
图片缓存
列表状态
Scroll位置
全部丢失,更推荐:
ts
Visibility.Hidden()
或者:
text
NavDestination
管理页面状态,避免频繁:
text
Create
Destroy
Create
Destroy
这种隐藏的性能损耗。
七、最容易被忽略的图片问题
很多 App 卡顿其实来自:
text
超大图片
例如,用户头像:
text
4000 × 3000
实际显示:
text
100 × 100
但系统仍然需要:
text
解码
缩放
渲染
尤其列表中:
text
几十张高清图
会造成:
text
内存暴涨
GC频繁
掉帧
使用缩略图
text
Thumbnail
图片缓存
text
ImageSource Cache
懒加载
text
按需解码
避免一次性加载全部资源。
八、流畅度优化的本质,其实是 Runtime 优化
很多人理解的性能优化:
text
动画优化
FPS优化
GPU优化
但从 HarmonyOS Runtime 的角度看,真正决定体验的是:
text
状态变化频率
组件重建次数
布局复杂度
主线程负载
内存分配次数
最终形成:
text
State
↓
Build
↓
Diff
↓
Layout
↓
Render
整个链路,任何一个环节出问题,都会表现成:
text
卡顿
而不是简单的:
text
帧率下降
总结
很多开发者优化 HarmonyOS App 时,最容易把注意力放在:
text
动画效果
组件库
GPU
但真正影响流畅度的,往往是下面这 5 个细节:
1、 滥用 @State
text
大状态
=
大范围重绘
2、 ForEach Key 错误
text
列表全部重建
3、 build() 中做复杂计算
text
CPU持续浪费
4、 主线程同步 IO
text
UI线程阻塞
5、 组件层级过深
text
Layout成本暴增
而更深层次来看:
HarmonyOS 的流畅,不是来自更快的 GPU,而是来自更聪明的 Runtime。
未来随着:
text
ArkUI
状态驱动
分布式任务
Agent Runtime
不断演进,性能优化的重点,也会逐渐从:
text
Render Optimization
转向:
text
Runtime Optimization
真正优秀的 HarmonyOS App,不一定拥有最炫的动画。但一定拥有:
最稳定、最轻量、最聪明的运行时。