Skip to content

ArkTS 异步编程

async/await、Promise、回调是 ArkTS 异步编程的核心。理解它们的区别和使用场景,是避免主线程卡顿的关键。


1. 异步编程的发展

回调 → Promise → async/await

ArkTS 支持所有三种方式,推荐顺序:async/await > Promise > 回调


2. Promise

2.1 基本用法

typescript
// 创建 Promise
const promise = new Promise<string>((resolve, reject) => {
    // 模拟异步操作
    setTimeout(() => {
        resolve('Hello')
    }, 1000)
})

// 处理结果
promise.then((value) => {
    console.log(value)  // "Hello"
}).catch((error) => {
    console.error(error)
}).finally(() => {
    console.log('完成')
})

2.2 Promise 链式调用

typescript
// ✅ 链式调用(避免回调地狱)
getUser()
    .then((user) => {
        return getUserPosts(user.id)
    })
    .then((posts) => {
        return getPostDetail(posts[0].id)
    })
    .then((detail) => {
        console.log(detail)
    })
    .catch((error) => {
        console.error('请求失败:', error)
    })

2.3 Promise 的状态

状态含义转换
Pending(等待)初始状态-
Fulfilled(成功)操作完成Pending → Fulfilled
Rejected(失败)操作失败Pending → Rejected

⚠️ 一旦状态确定,就无法再改变。


3. async/await

3.1 基本用法

typescript
// async 函数返回 Promise
async function fetchData(): Promise<string> {
    const response = await http.get('/api/data')
    return response.body
}

// await 只能在 async 函数中使用
async function process() {
    const data = await fetchData()  // 等待完成
    console.log(data)
}

3.2 对比:Promise vs async/await

typescript
// ❌ Promise 链式(可读性差)
getUser()
    .then((user) => {
        return getOrders(user.id)
    })
    .then((orders) => {
        return getOrderDetail(orders[0].id)
    })
    .then((detail) => {
        console.log(detail)
        showDetail(detail)
    })
    .catch((error) => {
        console.error(error)
    })

// ✅ async/await(更清晰)
async function processDetail() {
    try {
        const user = await getUser()
        const orders = await getOrders(user.id)
        const detail = await getOrderDetail(orders[0].id)
        showDetail(detail)
    } catch (error) {
        console.error(error)
    }
}

4. Promise.all — 并发请求

typescript
// 并发请求(并行执行,总时间 = 最慢的那个)
async function loadDashboard() {
    const [users, orders, stats] = await Promise.all([
        http.get('/api/users').then(r => r.json()),
        http.get('/api/orders').then(r => r.json()),
        http.get('/api/stats').then(r => r.json())
    ])

    return { users, orders, stats }
}

// 对比:串行请求(总时间 = 所有时间之和)
async function loadDashboardSerial() {
    const users = await http.get('/api/users').then(r => r.json())
    const orders = await http.get('/api/orders').then(r => r.json())
    const stats = await http.get('/api/stats').then(r => r.json())
    return { users, orders, stats }
}

5. 错误处理

5.1 try/catch

typescript
async function safeFetch(url: string) {
    try {
        const response = await http.get(url)
        if (response.statusCode !== 200) {
            throw new Error(`HTTP ${response.statusCode}`)
        }
        return response.json()
    } catch (error) {
        console.error('请求失败:', error)
        // 返回默认值或重试
        return getDefaultData()
    }
}

5.2 Promise.allSettled — 部分失败不中断

typescript
// 所有请求都执行,不管成功失败
async function loadAll() {
    const results = await Promise.allSettled([
        http.get('/api/users'),
        http.get('/api/orders'),
        http.get('/api/stats')
    ])

    // 逐个处理结果
    results.forEach((result, index) => {
        if (result.status === 'fulfilled') {
            console.log(`请求 ${index} 成功:`, result.value)
        } else {
            console.log(`请求 ${index} 失败:`, result.reason)
        }
    })
}

6. 异步编程的陷阱

6.1 主线程卡顿

typescript
@Component
struct Index {
    @State data: string = ''

    // ❌ 错误:同步操作放在主线程
    onLoad() {
        const result = this.synchronousWork()  // 耗时操作!
        this.data = result
    }

    // ✅ 正确:异步处理 + TaskPool
    async onLoadCorrect() {
        // 先更新 UI
        this.data = '加载中...'

        // 后台处理
        const result = await TaskPool.execute(() => {
            return this.synchronousWork()
        })

        this.data = result
    }
}

6.2 await 在 build 中

typescript
// ❌ 错误:build 中不能 await
@Component
struct Index {
    @State data: string = ''

    build() {
        // ❌ 编译错误!build 中不能写 await
        this.data = await fetchData()

        Text(this.data)
    }
}

// ✅ 正确:在生命周期或回调中处理
@Component
struct Index {
    @State data: string = ''

    aboutToAppear() {
        fetchData().then((d) => {
            this.data = d  // 在异步回调中修改 @State
        })
    }

    build() {
        Text(this.data)
    }
}

7. 面试高频考点

Q1: Promise.all 和 Promise.allSettled 的区别?

回答

  • Promise.all:任一请求失败,全部中断,返回错误
  • Promise.allSettled:所有请求都执行完,无论成败,返回每个请求的结果

Q2: async/await 相比 Promise 链式调用的优势?

回答:代码更清晰可读,错误处理用 try/catch 更符合直觉,变量可以直接使用不需要在每个 then 中重新获取。

Q3: 主线程卡顿的常见原因?

回答:在 aboutToAppear 或点击事件中进行同步 I/O 操作、复杂 JSON 解析或大量计算。解决方法:用 async/await 放到后台、用 TaskPool 处理耗时任务。


🐱 小猫提示:异步编程记住三个要点——async/await 优先、Promise.all 并行、build 中不能 await。这是高频考点。