Skip to content

渲染性能优化

鸿蒙渲染优化:120Hz 高刷、避免掉帧、LazyForEach、组件复用。


1. 渲染原理

1.1 渲染流水线

渲染流水线(每帧 16.67ms @ 60Hz)
├─ 输入事件处理 (2ms)
├─ 布局计算 (Layout) (3ms)
├─ 绘制命令生成 (3ms)
├─ GPU 渲染 (5ms)
├─ 合成与显示 (3.67ms)
└─ 总耗时 < 16.67ms(否则掉帧)

1.2 掉帧原因

常见掉帧原因:
├─ 布局过于复杂(嵌套过深)
├─ 大量组件同时渲染
├─ 主线程执行耗时操作
├─ 频繁触发状态更新
├─ 图片加载/解码阻塞
└─ 动画过于复杂

2. LazyForEach 懒加载

2.1 列表懒加载

typescript
// ❌ 错误:ForEach 渲染大量数据
@Entry
@Component
struct LongList {
    @State items: Array<Item> = []

    build() {
        Scroll() {
            Column() {
                ForEach(this.items, (item: Item) => {
                    ListItem({ item: item })
                })
            }
        }
    }
}
// 问题:1000 条数据会创建 1000 个组件,内存爆炸

// ✅ 正确:LazyForEach 懒加载
@Entry
@Component
struct LongList {
    @State items: Array<Item> = []

    build() {
        List() {
            LazyForEach(this.items, (item: Item) => {
                ListItem({ item: item })
            }, (item: Item) => item.id)  // 必须提供 key
        }
    }
}
// LazyForEach 只渲染可见区域 + 预加载区域

2.2 LazyForEach 优化

typescript
@Entry
@Component
struct OptimizedList {
    @State items: Array<Item> = []

    build() {
        List({
            space: 10,  //  item 间距
            initialIndex: 0  // 初始显示位置
        }) {
            LazyForEach(this.items, (item: Item) => {
                ListItem() {
                    Row() {
                        Image(item.avatar)
                            .width(50)
                            .height(50)
                        Column() {
                            Text(item.title)
                            Text(item.subtitle)
                        }
                    }
                    .width('100%')
                    .padding(10)
                }
            }, (item: Item) => item.id)
        }
        .onReachEnd(() => {
            // 滚动到底部加载更多
            this.loadMore()
        })
    }
}

3. 组件复用

3.1 避免重复创建

typescript
// ❌ 错误:每次 build 都创建新对象
@Entry
@Component
struct BadComponent {
    @State count: number = 0

    build() {
        Column() {
            // 每次都创建新数组,触发重新渲染
            ForEach([1, 2, 3, 4, 5], (item: number) => {
                Text(item.toString())
            })
        }
    }
}

// ✅ 正确:缓存数据
@Entry
@Component
struct GoodComponent {
    @State count: number = 0
    private dataList: number[] = [1, 2, 3, 4, 5]  // 缓存

    build() {
        Column() {
            ForEach(this.dataList, (item: number) => {
                Text(item.toString())
            })
        }
    }
}

3.2 条件渲染优化

typescript
// ❌ 错误:条件判断放在 build 内层
@Entry
@Component
struct BadCondition {
    @State show: boolean = false

    build() {
        Column() {
            ForEach(this.items, (item: Item) => {
                if (this.show) {  // 每次渲染都判断
                    Text(item.title)
                }
            })
        }
    }
}

// ✅ 正确:条件渲染
@Entry
@Component
struct GoodCondition {
    @State show: boolean = false

    build() {
        Column() {
            if (this.show) {
                ForEach(this.items, (item: Item) => {
                    Text(item.title)
                })
            }
        }
    }
}

4. 图片优化

4.1 图片加载

typescript
// ✅ 正确:指定宽高、使用缓存
Image($r('app.media.avatar'))
    .width(100)
    .height(100)
    .objectFit(ImageFit.Cover)
    .placeholder($r('app.media.placeholder'))  // 占位图
    .onComplete(() => {
        console.log('图片加载完成')
    })

5. 面试高频考点

Q1: 列表性能优化?

回答:使用 LazyForEach 替代 ForEach,只渲染可见区域;提供唯一 key;避免在 build 中创建对象。

Q2: 掉帧如何排查?

回答:使用 DevEco Profiler 查看渲染耗时,检查布局嵌套、主线程耗时操作、图片加载。


🐱 小猫提示:渲染优化记住 "LazyForEach、组件复用、避免重复创建、图片指定宽高、120Hz 适配"