在这里插入图片描述

网罗开发 (小红书、快手、视频号同名)

  大家好,我是 展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等方向。在移动端开发、鸿蒙开发、物联网、嵌入式、云原生、开源等领域有深厚造诣。

图书作者:《ESP32-C3 物联网工程开发实战》
图书作者:《SwiftUI 入门,进阶与实战》
超级个体:COC上海社区主理人
特约讲师:大学讲师,谷歌亚马逊分享嘉宾
科技博主:华为HDE/HDG

我的博客内容涵盖广泛,主要分享技术教程、Bug解决方案、开发工具使用、前沿科技资讯、产品评测与使用体验。我特别关注云服务产品评测、AI 产品对比、开发板性能测试以及技术报告,同时也会提供产品优缺点分析、横向对比,并分享技术沙龙与行业大会的参会体验。我的目标是为读者提供有深度、有实用价值的技术洞察与分析。

展菲:您的前沿技术领航员
👋 大家好,我是展菲!
📱 全网搜索“展菲”,即可纵览我在各大平台的知识足迹。
每周定时推送干货满满的技术长文,从新兴框架的剖析到运维实战的复盘,助您技术进阶之路畅通无阻。


引言

很多开发者第一次做鸿蒙 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

优化方案:异步初始化

async onWindowStageCreate() {

    await Promise.all([
        initDatabase(),
        initConfig()
    ])

}

非核心模块延迟加载:

setTimeout(() => {
    initUserData()
}, 0)

优化后:

1500ms
↓
700ms

这类优化在线上项目非常常见。

四、页面卡顿分析

假设用户反馈:

首页打开明显卡

首先不要看代码,先看:

页面渲染耗时

典型埋点:

const start = Date.now()

aboutToAppear()

const end = 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(let i=0;i<1000;i++){
    this.progress=i
}

每次赋值:

触发状态通知
↓
触发Diff
↓
触发Render

Profiler中会看到:

RenderNode
大量出现

优化方案

合并更新:

let progress = 0

for(let i=0;i<1000;i++){
    progress = i
}

this.progress = progress

或者:

store.batchUpdate(() => {

})

核心原则:

一次业务变更,只触发一次渲染。

七、CPU热点分析

如果出现:

页面不动也卡

通常是:

后台任务抢CPU

例如:

setInterval(() => {

    heavyCompute()

},100)

Profiler中会看到:

MainThread
持续占用

优化方案

迁移到 Worker

const worker = new worker.ThreadWorker(
  "entry/ets/workers/DataWorker.ts"
)

计算:

worker.postMessage(data)

主线程:

只负责UI

Worker:

负责计算

这是鸿蒙项目性能优化最有效的方法之一。

八、内存抖动分析

很多项目 FPS 正常,但:

每隔几秒卡一下

通常是:

GC频繁触发

典型代码:

setInterval(() => {

   let arr = []

   for(let i=0;i<10000;i++){
      arr.push({})
   }

},100)

产生大量临时对象。

优化方案

对象池

class ObjectPool<T> {

    private cache:T[]=[]

    acquire():T {}

    release(obj:T){}
}

效果:

减少GC
降低内存抖动

在聊天、IM、游戏场景非常常见。

九、鸿蒙性能优化最佳实践

经过多个大型项目实践后,性能优化基本可以总结为六条原则:

1. UI线程绝不做重计算

UI负责展示
Worker负责计算

2. Store控制刷新粒度

避免:

一个状态刷新整个页面

3. 列表必须懒加载

统一使用:

LazyForEach

4. 图片必须按需加载

避免:

原图直出

使用:

缩略图
WebP
缓存

5. 初始化分阶段执行

启动链路:

核心能力
↓
页面展示
↓
非核心能力

6. 建立性能基线

持续监控:

FPS
CPU
Memory
Startup
Render

不要等用户投诉。

总结

很多开发者认为:

性能优化
=
代码优化

实际上:

性能优化本质是定位系统瓶颈。

真正成熟的鸿蒙团队优化流程应该是:

监控
 ↓
发现异常
 ↓
Profiler分析
 ↓
定位热点
 ↓
代码优化
 ↓
数据验证

而不是:

感觉卡
 ↓
疯狂改代码
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐