Skip to content

ArkTS 性能最佳实践

ArkTS 性能优化的核心原则:编译期优化、减少运行时开销、利用 AOT 特性。


1. ArkTS 性能优化全景

编译期优化 (AOT)
├── 静态类型 → Hidden Class
├── 无 any → 跳过类型检查
├── 无 eval → 代码优化
└── 无 var → 变量提升消除

运行时优化
├── 对象池 → 减少 GC
├── 对象不变性 → 缓存优化
├── 按需渲染 → LazyForEach
└── 减少 build 复杂度 → 首屏优化

2. 类型优化

2.1 避免 any

typescript
// ❌ 任何类型,编译器无法优化
let data: any = fetchData()

// ✅ 具体类型,编译器生成 Hidden Class
let data: ResponseData = fetchData()

// ✅ Record 类型,精确约束
let dict: Record<string, number> = {}

2.2 使用 Record 代替 {} 字面量

typescript
// ❌ 普通对象,性能较差
let obj: object = { name: '小明', age: 25 }

// ✅ Record,Hidden Class 优化
let obj: Record<string, string | number> = {
    name: '小明',
    age: 25
}

2.3 类型推断优先

typescript
// ✅ 编译器自动推导,减少冗余声明
let name = '小明'        // string
let count = 42           // number
let items = ['a', 'b']   // string[]

// 需要显式声明的场景:
// 1. 接口/类型别名
// 2. 函数返回值
// 3. 可能为 null/undefined
let age: number | null = null

3. 对象优化

3.1 Hidden Class 原理

JavaScript/V8/ArkCompiler 使用 Hidden Class(隐藏类)优化对象属性访问:

对象创建 → 确定属性布局 → 生成 Hidden Class → 快速属性访问

{ name: '小明', age: 25 }

Hidden Class: { [0]: name(offset 0), [1]: age(offset 8) }

属性访问: O(1) 直接内存偏移访问

3.2 保持对象形状不变

typescript
// ✅ 推荐:对象形状一致
function process1() {
    let obj1 = { name: '小明', age: 25 }    // Class A
    let obj2 = { name: '小红', age: 20 }    // 同一 Class A
    // obj1 和 obj2 共享 Hidden Class,快速
}

// ❌ 不推荐:动态添加属性
function process2() {
    let obj = { name: '小明' }                // Class A
    obj.age = 25                              // 创建 Class B!
    let obj2 = { name: '小红', age: 20 }    // Class C
    // obj、obj2 不在同一 Hidden Class,需要类型检查
}

3.3 使用 as const

typescript
// 减少运行时分配
const CONFIG = {
    apiUrl: 'https://api.example.com',
    timeout: 5000,
    retries: 3
} as const  // 编译期确定,运行时共享同一引用

4. 数组操作优化

4.1 避免频繁 push/pop 在 build 中

typescript
@Component
struct Index {
    @State items: string[] = []

    // ❌ 在 build 中修改数组
    build() {
        this.items.push('item')  // ❌ 不应在 build 中操作
    }

    // ✅ 在回调或生命周期中修改
    addItem() {
        this.items.push('item')  // ✅ @State 检测到变化
    }
}

4.2 使用 LazyForEach 替代 ForEach

typescript
// ❌ ForEach:全量渲染(数据量大时卡顿)
ForEach(this.largeList, (item) => {
    ListItem(item)
})

// ✅ LazyForEach:按需渲染(推荐)
LazyForEach(this.dataSource, (item) => {
    ListItem(item)
})

4.3 数组不可变性

typescript
// ✅ 通过不可变赋值触发刷新
@Component
struct Index {
    @State list: string[] = ['a', 'b', 'c']

    addItem(item: string) {
        // ❌ 直接 push 可能不触发刷新
        this.list.push(item)

        // ✅ 创建新数组触发刷新
        this.list = [...this.list, item]

        // ✅ 或者替换数组引用
        this.list = [...this.list]
    }
}

5. 字符串优化

5.1 字符串拼接

typescript
// ❌ 循环拼接字符串(频繁创建新对象)
let result = ''
for (let i = 0; i < 10000; i++) {
    result += 'item'
}

// ✅ 使用 Array.join(更高效)
let result = Array.from({ length: 10000 }, () => 'item').join('')

5.2 字符串模板

typescript
// ✅ 模板字符串(编译期优化)
let name = '小明'
let greeting = `Hello, ${name}!`

// ✅ 多行字符串
let html = `
    <div>
        <p>${name}</p>
    </div>
`

6. 函数调用优化

6.1 减少函数调用开销

typescript
// ❌ 循环中频繁调用函数
for (let i = 0; i < 10000; i++) {
    this.formatItem(items[i])  // 函数调用开销
}

// ✅ 内联处理(减少调用开销)
for (let i = 0; i < 10000; i++) {
    let item = items[i]
    let formatted = `${item.name} - ${item.value}`  // 内联
}

6.2 使用静态方法

typescript
class Utils {
    // 静态方法:无需实例化
    static formatDate(date: Date): string {
        return date.toISOString()
    }

    static isEmpty(value: any): boolean {
        return value === null || value === undefined || value === ''
    }
}

// 调用
Utils.formatDate(new Date())
Utils.isEmpty('')

7. build() 函数优化

7.1 build() 中的限制

限制原因
不能写 console.logbuild 只执行 UI 描述
不能定义局部变量编译期优化需要纯描述
不能直接调用非 @Builder 函数保持纯描述语义

7.2 优化 build 复杂度

typescript
// ❌ build 中嵌套太多组件(渲染慢)
build() {
    Column() {
        Row() {  // 第2层
            Column() {  // 第3层
                Row() {  // 第4层
                    Column() {  // 第5层...
                        Text('...')
                    }
                }
            }
        }
    }
}

// ✅ 提取为子组件
@Component
struct Header { ... }
@Component
struct Content { ... }
@Component
struct Footer { ... }

build() {
    Column() {
        Header()
        Content()
        Footer()
    }
}

8. 面试高频考点

Q1: Hidden Class 是什么?如何优化?

回答:ArkCompiler 在编译期为对象生成隐藏类(属性布局),运行时通过内存偏移快速访问属性。优化方式:保持对象形状一致、使用 Record 类型、使用 as const。

Q2: build() 函数有哪些限制?

回答:只能包含 UI 描述代码,不能写 console.log、不能定义局部变量、不能直接调用非 @Builder 装饰的函数。原因是 build 需要编译期纯描述优化。

Q3: ForEach 和 LazyForEach 的区别?

回答:ForEach 全量渲染,适合少量数据;LazyForEach 按需渲染(只渲染可视区域),配合 IDataSource 使用,长列表必用。


🐱 小猫提示:性能优化的核心思路就是**"能编译期做的绝不放到运行时"**。记住 Hidden Class、LazyForEach、build 复杂度这三个关键词。