大家好,我是展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等方向。在移动端开发、鸿蒙开发、物联网、嵌入式、云原生、开源等领域有深厚造诣。
图书作者:《ESP32-C3 物联网工程开发实战》
图书作者:《SwiftUI 入门,进阶与实战》
超级个体:COC上海社区主理人
特约讲师:大学讲师,谷歌亚马逊分享嘉宾
科技博主:华为HDE/HDG
我的博客内容涵盖广泛,主要分享技术教程、Bug解决方案、开发工具使用、前沿科技资讯、产品评测与使用体验。我特别关注云服务产品评测、AI 产品对比、开发板性能测试以及技术报告,同时也会提供产品优缺点分析、横向对比,并分享技术沙龙与行业大会的参会体验。我的目标是为读者提供有深度、有实用价值的技术洞察与分析。
展菲:您的前沿技术领航员
👋 大家好,我是展菲!
📱 全网搜索“展菲”,即可纵览我在各大平台的知识足迹。
每周定时推送干货满满的技术长文,从新兴框架的剖析到运维实战的复盘,助您技术进阶之路畅通无阻。
文章目录
- 引言
- 一、鸿蒙 App 的卡顿到底发生在哪里
- 二、建立性能分析体系
- 三、启动卡顿分析
- 错误示例
- 优化方案:异步初始化
- 四、页面卡顿分析
- 五、列表滑动卡顿分析
- 正确方案
- 六、状态刷新风暴分析
- 优化方案
- 七、CPU热点分析
- 优化方案
- 八、内存抖动分析
- 优化方案
- 九、鸿蒙性能优化最佳实践
- 1. UI线程绝不做重计算
- 2. Store控制刷新粒度
- 3. 列表必须懒加载
- 4. 图片必须按需加载
- 5. 初始化分阶段执行
- 6. 建立性能基线
- 总结
引言
很多开发者第一次做鸿蒙 App 优化时,都会有一个误区:
感觉卡 就开始优化代码例如:
- 减少组件
- 减少接口
- 删除动画
- 修改状态管理
忙活一周后发现:
FPS没变 启动速度没变 用户依旧反馈卡顿原因很简单:
没有定位,就没有优化。
在大型鸿蒙项目里,真正的性能优化流程应该是:
发现问题 ↓ 定位问题 ↓ 量化问题 ↓ 验证优化而不是:
感觉哪里卡 就改哪里一、鸿蒙 App 的卡顿到底发生在哪里
先理解一个概念,60FPS 的设备意味着:\frac{1000}{60}=16.67ms,系统每 16.67ms 必须完成:
事件处理 状态计算 布局计算 绘制提交 GPU渲染如果某个环节超时:
16.67ms ↑ 突破那么:
当前帧丢失用户看到的就是:
滑动不跟手 动画掉帧 页面卡死因此性能优化的核心目标其实只有一个:
让关键路径始终小于一帧预算。
二、建立性能分析体系
很多团队优化性能时最大的问题:
没有指标必须先建立:
性能指标体系推荐监控:
| 指标 | 目标 |
|---|---|
| FPS | >55 |
| 首帧时间 | <500ms |
| 页面打开时间 | <1000ms |
| CPU占用 | <60% |
| 内存占用 | 稳定增长 |
| GC次数 | 尽量少 |
| 网络耗时 | 可追踪 |
如果这些数据拿不到:
优化无法量化三、启动卡顿分析
大型鸿蒙项目最常见的问题:
冷启动慢用户点击图标:
点击 ↓ 白屏 ↓ 页面出现可能经历:
Ability创建 Store初始化 数据库初始化 网络初始化 资源加载错误示例
onWindowStageCreate(){initDatabase()initNetwork()initUserData()initConfig()}所有初始化串行执行,启动时间:
300ms + 500ms + 400ms + 300ms = 1500ms优化方案:异步初始化
asynconWindowStageCreate(){awaitPromise.all([initDatabase(),initConfig()])}非核心模块延迟加载:
setTimeout(()=>{initUserData()},0)优化后:
1500ms ↓ 700ms这类优化在线上项目非常常见。
四、页面卡顿分析
假设用户反馈:
首页打开明显卡首先不要看代码,先看:
页面渲染耗时典型埋点:
conststart=Date.now()aboutToAppear()constend=Date.now()console.info(`render cost=${end-start}`)进一步分析:
组件创建耗时 ↓ 状态初始化耗时 ↓ 接口请求耗时找到最重环节。
五、列表滑动卡顿分析
这是线上最常见问题,例如电商首页:
商品列表 2000+很多项目这样写:
ForEach(products,item=>{ProductCard({item})})问题:
一次创建全部节点Profiler 可以看到:
BuildComponent 耗时暴涨正确方案
使用 LazyForEach
List(){LazyForEach(dataSource,(item)=>{ListItem(){ProductCard({item})}})}优化后:
组件数量 2000 ↓ 20内存占用和渲染时间都会明显下降。
六、状态刷新风暴分析
这是 ArkUI 项目中特别常见的问题,例如:
for(leti=0;i<1000;i++){this.progress=i}每次赋值:
触发状态通知 ↓ 触发Diff ↓ 触发RenderProfiler中会看到:
RenderNode 大量出现优化方案
合并更新:
letprogress=0for(leti=0;i<1000;i++){progress=i}this.progress=progress或者:
store.batchUpdate(()=>{})核心原则:
一次业务变更,只触发一次渲染。
七、CPU热点分析
如果出现:
页面不动也卡通常是:
后台任务抢CPU例如:
setInterval(()=>{heavyCompute()},100)Profiler中会看到:
MainThread 持续占用优化方案
迁移到 Worker
constworker=newworker.ThreadWorker("entry/ets/workers/DataWorker.ts")计算:
worker.postMessage(data)主线程:
只负责UIWorker:
负责计算这是鸿蒙项目性能优化最有效的方法之一。
八、内存抖动分析
很多项目 FPS 正常,但:
每隔几秒卡一下通常是:
GC频繁触发典型代码:
setInterval(()=>{letarr=[]for(leti=0;i<10000;i++){arr.push({})}},100)产生大量临时对象。
优化方案
对象池
classObjectPool<T>{privatecache:T[]=[]acquire():T{}release(obj:T){}}效果:
减少GC 降低内存抖动在聊天、IM、游戏场景非常常见。
九、鸿蒙性能优化最佳实践
经过多个大型项目实践后,性能优化基本可以总结为六条原则:
1. UI线程绝不做重计算
UI负责展示 Worker负责计算2. Store控制刷新粒度
避免:
一个状态刷新整个页面3. 列表必须懒加载
统一使用:
LazyForEach4. 图片必须按需加载
避免:
原图直出使用:
缩略图 WebP 缓存5. 初始化分阶段执行
启动链路:
核心能力 ↓ 页面展示 ↓ 非核心能力6. 建立性能基线
持续监控:
FPS CPU Memory Startup Render不要等用户投诉。
总结
很多开发者认为:
性能优化 = 代码优化实际上:
性能优化本质是定位系统瓶颈。
真正成熟的鸿蒙团队优化流程应该是:
监控 ↓ 发现异常 ↓ Profiler分析 ↓ 定位热点 ↓ 代码优化 ↓ 数据验证而不是:
感觉卡 ↓ 疯狂改代码