鸿蒙异步并发 async/await 最佳实践,代码瞬间优雅

Hello,兄弟们,我是 V 哥!

还记得以前写 Android 或者早期 JavaScript 的时候,那个传说中的**"回调地狱"**吗?

javascript 复制代码
// 伪代码演示:让人崩溃的金字塔
login(user, (res1) => {
  getUserInfo(res1.id, (res2) => {
    getOrders(res2.token, (res3) => {
      getDetail(res3.orderId, (res4) => {
        // 终于结束了... 代码已经缩进到屏幕外边了
      })
    })
  })
})

这种代码,维护起来简直是噩梦!但在鸿蒙 ArkTS 的 API 21 环境下,兄弟们千万别再这么写了!ArkTS 是基于 TypeScript 的,它原生支持非常强大的 async/await 语法。

今天 V 哥就带你把这段"金字塔"拍平,用 同步的逻辑写异步的代码,优雅得像喝下午茶一样!


核心心法:把"等待"变成"暂停"

兄弟们,记住 V 哥这两个口诀:

  1. async:加在函数定义前面,表示"这里面有耗时的活儿"。
  2. await :加在耗时的调用前面,表示"等着这儿干完,再去干下一行,但别把界面卡死"。

有了这两个神器,异步代码写出来就像在写小学作文,从上到下,一行一行读,逻辑清晰无比。


实战代码案例

为了让大家直观感受,V 哥写了一个完整的 Demo。咱们模拟三个常见的真实场景:

  1. 串行执行:先登录,再拿用户信息。
  2. 并发执行:同时拉取"广告配置"和"首页推荐"。
  3. 异常处理:优雅地捕获网络错误。

操作步骤: 打开你的 DevEco Studio 6.0,新建一个 ArkTS 页面,把下面的代码完整复制进去,直接运行!

typescript 复制代码
import promptAction from '@ohos.promptAction';

/**
 * V哥的模拟网络请求类
 * 在真实项目中,这里会换成 httpRequest 或者 网络库
 */
class NetworkSimulator {
  // 模拟一个异步耗时操作,返回 Promise
  static request(apiName: string, data: string, delay: number): Promise<string> {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        // 模拟 20% 的概率失败
        if (Math.random() < 0.2) {
          reject(new Error(`${apiName} 请求失败,网络不给力!`));
        } else {
          resolve(`${apiName} 返回的数据: ${data}`);
        }
      }, delay);
    });
  }
}

@Entry
@Component
struct AsyncAwaitDemo {
  @State resultLog: string = 'V哥准备好输出日志了...';
  @State isLoading: boolean = false;

  build() {
    Column() {
      Text('鸿蒙 async/await 实战实验室')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 30, bottom: 20 })

      // 场景一:串行执行
      Button('场景1:串行执行 (登录 -> 获取信息)')
        .width('90%')
        .margin({ bottom: 15 })
        .onClick(() => {
          this.testSequential();
        })

      // 场景二:并发执行
      Button('场景2:并发执行 (同时拉取配置和广告)')
        .width('90%')
        .margin({ bottom: 15 })
        .onClick(() => {
          this.testParallel();
        })

      // 场景三:异常捕获
      Button('场景3:异常捕获 (模拟失败重试)')
        .width('90%')
        .margin({ bottom: 15 })
        .onClick(() => {
          this.testErrorHandling();
        })

      // 日志显示区域
      Column() {
        Text(this.resultLog)
          .fontSize(14)
          .fontColor('#333333')
          .width('100%')
      }
      .width('90%')
      .height('40%')
      .padding(15)
      .backgroundColor('#F1F3F5')
      .borderRadius(10)
      .margin({ top: 20 })

      if (this.isLoading) {
        LoadingProgress()
          .width(30)
          .height(30)
          .margin({ top: 20 })
          .color(Color.Blue)
      }

    }
    .width('100%')
    .height('100%')
    .padding({ left: 20, right: 20 })
  }

  /**
   * V哥解析:场景1 - 串行执行
   * 特点:一步接一步,下一步依赖上一步的结果。
   * 代码逻辑:完全是线性的,像同步代码一样易读!
   */
  async testSequential() {
    this.isLoading = true;
    this.resultLog = '1. 开始登录...\n';

    try {
      // V哥重点:await 会暂停函数执行,直到 Promise resolve
      // 这里模拟先登录,耗时 1000ms
      let loginRes = await NetworkSimulator.request('LoginAPI', 'Token123', 1000);
      this.resultLog += `   ${loginRes}\n`;

      this.resultLog += '2. 正在获取用户信息...\n';
      // 依赖上面的 Token,继续 await
      let userRes = await NetworkSimulator.request('GetUserInfo', 'V哥的大名', 800);
      this.resultLog += `   ${userRes}\n`;

      this.resultLog += '✅ 全部完成!(串行总耗时约 1.8s)';
      
      promptAction.showToast({ message: '串行执行完成' });

    } catch (error) {
      this.resultLog += `❌ 出错了: ${error.message}`;
    } finally {
      this.isLoading = false;
    }
  }

  /**
   * V哥解析:场景2 - 并发执行
   * 特点:两个请求互不依赖,同时发出,谁先回来谁先结束。
   * 优势:速度最快!总耗时 = 两个请求中最慢的那个,而不是两者之和。
   */
  async testParallel() {
    this.isLoading = true;
    this.resultLog = '1. 同时启动多个任务...\n';

    // 记录开始时间
    const startTime = Date.now();

    try {
      // V哥重点:Promise.all()
      // 把所有要并发的 Promise 放进数组里
      // await 会等数组里所有的 Promise 都 resolve 才继续
      let results = await Promise.all([
        NetworkSimulator.request('GetConfig', '系统配置', 1500), // 假设这个慢
        NetworkSimulator.request('GetBanner', '广告图片', 1000)  // 假设这个快
      ]);

      // results 是一个数组,顺序和你传入的顺序一致,不管谁先回来
      this.resultLog += `   ${results[0]}\n`; // 第一个结果
      this.resultLog += `   ${results[1]}\n`; // 第二个结果

      const duration = Date.now() - startTime;
      this.resultLog += `✅ 全部完成!(并发总耗时约 ${duration}ms,比串行快!)`;
      
      promptAction.showToast({ message: '并发执行完成' });

    } catch (error) {
      this.resultLog += `❌ 出错了: ${error.message}`;
    } finally {
      this.isLoading = false;
    }
  }

  /**
   * V哥解析:场景3 - 异常处理
   * 特点:async/await 下,我们用 try...catch...finally 代替 .then().catch()
   * 这比传统的 Promise 链式调用要直观得多,像处理 Java 异常一样舒服。
   */
  async testErrorHandling() {
    this.isLoading = true;
    this.resultLog = '尝试发送请求 (模拟20%失败率)...\n';

    try {
      // 这里的请求可能会抛出 Error
      let data = await NetworkSimulator.request('RiskyAPI', '试试运气', 1000);
      this.resultLog += `   成功: ${data}`;
      promptAction.showToast({ message: '请求成功' });

    } catch (error) {
      // V哥重点:一旦任何一步 await 报错,直接跳进 catch
      this.resultLog += `   捕获到异常: ${error.message}\n`;
      this.resultLog += `   这里可以进行重试逻辑...`;
      
      promptAction.showToast({ message: '请求被拦截' });

    } finally {
      // V哥重点:finally 无论成功失败都会执行
      // 适合用来关闭 Loading 弹窗
      this.isLoading = false;
    }
  }
}

运行结果:


V 哥的代码深度解析

兄弟们,代码能跑了,咱们得懂原理,不然面试的时候要挂!

1. 为什么 async/await 不会卡死界面?

这就是并发编程的魔力。 当你写 let res = await someRequest() 的时候,ArkTS 的运行时会把当前任务的挂起,把主线程的控制权交还给 UI 系统。 这就好比你去排队买奶茶,你叫服务员做奶茶(发起请求),你站在旁边等(await),但**店里的其他人(UI线程)**依然可以继续进店买东西。只有当你的奶茶好了(Promise resolve),你才拿着奶茶走人(代码继续往下走)。

2. Promise.all 是性能优化的利器

在场景 2 中,V 哥演示了 Promise.all。 如果你的首页有 5 个接口,互不依赖,你千万别写 5 行 await:

typescript 复制代码
// ❌ 错误写法:慢得要死
let a = await req1(); // 等1秒
let b = await req2(); // 再等1秒
// ... 总耗时 5秒
typescript 复制代码
// ✅ V 哥正确写法:飞快
let results = await Promise.all([req1(), req2(), req3(), req4(), req5()]);
// 总耗时 = 最慢的那个接口 (假设是 1.2秒)

这可是实打实的性能提升,用户打开 App 的速度直接肉眼可见变快!

3. 不要忘记了 try-catch

以前写 Promise 链,如果不加 .catch(),报错了可能就像石沉大海,静默失败。 用了 async/await一定要 包裹在 try...catch 里。这是对自己代码负责,也是对用户负责。


总结

来来来,V 哥稍微小结一下:

  1. 逻辑复杂?async/await 拍平金字塔。
  2. 请求多且慢?Promise.all 并行加速。
  3. 怕出错?try/catch 稳稳兜底。

在 DevEco Studio 6.0 里,这套组合拳用熟练了,你的代码质量和开发效率绝对能甩开同行一条街。

我是 V 哥,拒绝回调地狱,从今天开始!咱们下期见!👋

相关推荐
威哥爱编程1 小时前
你的手势冲突解决了吗?鸿蒙事件拦截机制全解析
harmonyos·arkts·arkui
2501_948122632 小时前
React Native for OpenHarmony 实战:Steam 资讯 App 服务条款实现
javascript·react native·react.js·游戏·ecmascript·harmonyos
鸣弦artha2 小时前
Flutter 框架跨平台鸿蒙开发 —— Image Widget 占位符技术
flutter·华为·harmonyos
世人万千丶3 小时前
鸿蒙跨端框架Flutter学习day 2、常用UI组件-层叠布局 Stack & Positioned
学习·flutter·ui·实时互动·harmonyos·鸿蒙
酒醉的胡铁3 小时前
uniapp运行到鸿蒙证书配置
服务器·uni-app·harmonyos
hefengbao5 小时前
【京墨文库】安卓版 v.16.1, 鸿蒙版 v1.2.1发布
华为·harmonyos
小学生波波6 小时前
HarmonyOS6 - XComponent与AVPlayer实现视频播放功能
arkts·鸿蒙·鸿蒙系统·视频播放·鸿蒙开发·harmonyos6
lili-felicity6 小时前
React Native for HarmonyOS (鸿蒙) 实战精讲:2D/3D 变换全场景
react native·3d·harmonyos
哈哈你是真的厉害6 小时前
React Native 鸿蒙跨平台开发:Badge 徽标
react native·react.js·harmonyos