OpenHarmony异步编程模型:Promise与Async/Await最佳实践

OpenHarmony异步编程模型:Promise与Async/Await最佳实践

【免费下载链接】docs OpenHarmony documentation | OpenHarmony开发者文档 【免费下载链接】docs 项目地址: https://gitcode.com/openharmony/docs

引言:异步编程的痛点与解决方案

在OpenHarmony应用开发中,你是否经常遇到以下问题:网络请求阻塞UI线程导致界面卡顿?复杂的回调嵌套形成"回调地狱"难以维护?异步操作的错误处理繁琐且分散?本文将系统讲解OpenHarmony中的Promise与Async/Await异步编程模型,通过实例代码和最佳实践,帮助你彻底解决这些痛点,编写出高效、清晰、可维护的异步代码。

读完本文后,你将能够:

  • 理解Promise的工作原理和状态流转机制
  • 掌握Async/Await语法糖的使用方法
  • 熟练处理异步操作中的错误和异常
  • 优化复杂异步流程的代码结构
  • 避免常见的异步编程陷阱

1. OpenHarmony异步编程基础

1.1 为什么需要异步编程

OpenHarmony应用开发中,许多操作如网络请求、文件读写、数据库操作等都是耗时的。如果采用同步方式执行这些操作,会阻塞主线程(UI线程),导致应用界面卡顿、无响应,严重影响用户体验。

// 错误示例:同步网络请求阻塞UI
function syncNetworkRequest() {
  const result = httpRequestSync('https://api.example.com/data'); // 同步请求,阻塞UI
  updateUI(result); // UI更新被阻塞
}

1.2 异步编程模型演进

OpenHarmony支持多种异步编程模型,按出现顺序依次为:

  • 回调函数(Callbacks)
  • Promise
  • Async/Await(Promise语法糖)

其中,Promise和Async/Await是当前推荐的主流方案,它们解决了回调函数的诸多问题,提供了更优雅的异步编程体验。

2. Promise详解

2.1 Promise基本概念

Promise(承诺)是一个对象,代表一个异步操作的最终完成(或失败)及其结果值。Promise有三种状态:

  • Pending(进行中):初始状态,既不是成功,也不是失败
  • Fulfilled(已成功):操作成功完成
  • Rejected(已失败):操作失败

mermaid

2.2 创建Promise对象

使用new Promise()构造函数创建Promise对象,该构造函数接受一个执行器(executor)函数作为参数,该函数有两个参数:resolvereject

// 创建一个Promise对象
const promise = new Promise((resolve, reject) => {
  // 异步操作
  setTimeout(() => {
    const success = true;
    if (success) {
      resolve("操作成功的结果"); // 成功时调用resolve
    } else {
      reject(new Error("操作失败的原因")); // 失败时调用reject
    }
  }, 1000);
});

2.3 Promise常用方法

2.3.1 then()方法

then()方法用于指定Promise对象状态变为成功(fulfilled)时的回调函数。

promise.then((result) => {
  console.log("成功:", result);
});
2.3.2 catch()方法

catch()方法用于指定Promise对象状态变为失败(rejected)时的回调函数。

promise.catch((error) => {
  console.error("失败:", error.message);
});
2.3.3 finally()方法

finally()方法用于指定无论Promise对象状态是成功还是失败都会执行的回调函数。

promise.finally(() => {
  console.log("无论成功失败都会执行");
});

2.4 Promise链式调用

Promise的一大优势是支持链式调用,可以将多个异步操作按顺序执行,避免回调地狱。

// 链式调用示例
fetchUserData()
  .then(user => {
    console.log("用户数据:", user);
    return fetchUserPosts(user.id); // 返回新的Promise
  })
  .then(posts => {
    console.log("用户帖子:", posts);
    return fetchPostComments(posts[0].id); // 返回新的Promise
  })
  .then(comments => {
    console.log("帖子评论:", comments);
  })
  .catch(error => {
    console.error("出错了:", error); // 捕获整个链中的错误
  })
  .finally(() => {
    console.log("所有操作完成");
  });

2.5 Promise静态方法

2.5.1 Promise.all()

当需要等待多个异步操作全部完成时,使用Promise.all()。它接收一个Promise数组,返回一个新的Promise,当所有Promise都成功时才成功,只要有一个失败就立即失败。

// 并行执行多个异步操作
const promise1 = fetchData1();
const promise2 = fetchData2();
const promise3 = fetchData3();

Promise.all([promise1, promise2, promise3])
  .then(results => {
    const [result1, result2, result3] = results;
    console.log("所有操作成功完成", result1, result2, result3);
  })
  .catch(error => {
    console.error("至少有一个操作失败", error);
  });
2.5.2 Promise.race()

Promise.race()接收一个Promise数组,返回一个新的Promise,只要数组中的任何一个Promise状态改变(成功或失败),它就会立即以相同的状态返回。

// 超时控制示例
const fetchWithTimeout = (url, timeout = 5000) => {
  return Promise.race([
    fetch(url),
    new Promise((_, reject) => {
      setTimeout(() => {
        reject(new Error(`请求超时(${timeout}ms)`));
      }, timeout);
    })
  ]);
};

fetchWithTimeout("https://api.example.com/data")
  .then(response => response.json())
  .then(data => console.log("数据:", data))
  .catch(error => console.error("错误:", error.message));
2.5.3 Promise.resolve()和Promise.reject()
  • Promise.resolve(value): 返回一个以给定值解析后的Promise对象
  • Promise.reject(reason): 返回一个带有拒绝原因的Promise对象
// Promise.resolve示例
Promise.resolve("直接成功").then(value => console.log(value));

// Promise.reject示例
Promise.reject(new Error("直接失败")).catch(error => console.error(error));

3. Async/Await:Promise的语法糖

3.1 基本语法

Async/Await是ES2017引入的语法糖,基于Promise实现,提供了更简洁、更接近同步代码风格的异步编程方式。

使用规则:

  • async关键字声明异步函数
  • await关键字只能在async函数内部使用
  • await后面跟一个Promise对象
// Async/Await基本用法
async function fetchData() {
  try {
    const response = await fetch("https://api.example.com/data");
    const data = await response.json();
    console.log("数据:", data);
    return data;
  } catch (error) {
    console.error("错误:", error);
    throw error; // 可以将错误向上抛出
  }
}

// 调用异步函数
fetchData().then(result => console.log("处理结果:", result));

3.2 错误处理

Async/Await使用try/catch语句处理错误,相比Promise的catch()方法,更接近同步代码的错误处理方式,代码结构更清晰。

// 错误处理示例
async function asyncOperation() {
  try {
    const result1 = await operation1();
    const result2 = await operation2(result1);
    const result3 = await operation3(result2);
    return result3;
  } catch (error) {
    console.error("捕获到错误:", error);
    // 错误处理逻辑
    return fallbackValue; // 可以返回默认值
  } finally {
    // 无论成功失败都会执行的清理工作
    cleanup();
  }
}

3.3 并行执行

在Async/Await中实现并行执行异步操作,可以结合Promise.all()

// 并行执行示例
async function parallelOperations() {
  try {
    // 同时启动多个异步操作
    const promise1 = operation1();
    const promise2 = operation2();
    const promise3 = operation3();
    
    // 等待所有操作完成
    const [result1, result2, result3] = await Promise.all([promise1, promise2, promise3]);
    
    // 处理结果
    return processResults(result1, result2, result3);
  } catch (error) {
    console.error("并行操作出错:", error);
  }
}

4. OpenHarmony中的异步API应用

4.1 文件操作

OpenHarmony的文件操作API是异步的,使用Promise封装:

import fs from '@ohos.file.fs';

async function readFileContent(filePath: string): Promise<string> {
  try {
    // 打开文件
    const file = await fs.open(filePath, fs.OpenMode.READ_ONLY);
    
    // 读取文件内容
    const buffer = new ArrayBuffer(4096);
    const readLen = await fs.read(file.fd, buffer);
    
    // 关闭文件
    await fs.close(file.fd);
    
    // 转换为字符串并返回
    return String.fromCharCode.apply(null, new Uint8Array(buffer.slice(0, readLen)));
  } catch (error) {
    console.error(`读取文件失败: ${error}`);
    throw error;
  }
}

4.2 网络请求

使用@ohos.net.http模块进行网络请求:

import http from '@ohos.net.http';

async function fetchData(url: string): Promise<any> {
  // 创建HTTP请求
  let request = http.createHttp();
  
  try {
    // 发起请求
    let response = await request.request(
      url,
      {
        method: http.RequestMethod.GET,
        header: {
          'Content-Type': 'application/json'
        },
        connectTimeout: 60000,
        readTimeout: 60000
      }
    );
    
    // 处理响应
    if (response.responseCode === http.ResponseCode.OK) {
      return JSON.parse(response.result as string);
    } else {
      throw new Error(`请求失败: ${response.responseCode}`);
    }
  } catch (error) {
    console.error(`网络请求错误: ${error}`);
    throw error;
  } finally {
    // 销毁HTTP请求
    request.destroy();
  }
}

4.3 数据库操作

关系型数据库操作示例:

import relationalStore from '@ohos.data.relationalStore';

async function queryDatabase(context: Context, sql: string, params: Array<string | number> = []): Promise<relationalStore.ResultSet> {
  try {
    // 获取数据库连接
    const store = await relationalStore.getRdbStore(context, {
      name: 'app.db',
      securityLevel: relationalStore.SecurityLevel.S1
    });
    
    // 执行查询
    return await store.querySql(sql, params);
  } catch (error) {
    console.error(`数据库查询失败: ${error}`);
    throw error;
  }
}

5. 最佳实践与性能优化

5.1 避免过度串行化

不要将可以并行的异步操作串行执行,这会显著降低性能:

// 不好的做法:不必要的串行执行
async function badPractice() {
  const data1 = await fetchData1(); // 100ms
  const data2 = await fetchData2(); // 100ms
  const data3 = await fetchData3(); // 100ms
  // 总时间: ~300ms
}

// 好的做法:并行执行
async function goodPractice() {
  const promise1 = fetchData1(); // 立即开始
  const promise2 = fetchData2(); // 立即开始
  const promise3 = fetchData3(); // 立即开始
  
  const [data1, data2, data3] = await Promise.all([promise1, promise2, promise3]);
  // 总时间: ~100ms (取决于最慢的那个)
}

5.2 限制并发数量

当有大量异步操作需要执行时,不应同时启动所有操作(可能导致资源耗尽),而应限制并发数量:

// 限制并发数量示例
async function limitedParallel(tasks: Array<() => Promise<any>>, limit: number): Promise<any[]> {
  const results = [];
  const executing = new Set();
  
  for (const task of tasks) {
    // 创建一个Promise,当任务完成时从executing集合中移除
    const promise = task().then(result => {
      results.push(result);
      executing.delete(promise);
    });
    
    executing.add(promise);
    
    // 如果达到并发限制,等待任一任务完成
    if (executing.size >= limit) {
      await Promise.race(executing);
    }
  }
  
  // 等待所有剩余任务完成
  await Promise.all(executing);
  
  return results;
}

// 使用示例
const tasks = Array.from({length: 20}, (_, i) => () => fetchData(i));
limitedParallel(tasks, 5).then(results => console.log("所有结果:", results));

5.3 异步操作取消

OpenHarmony中可以使用AbortController来取消异步操作:

// 异步操作取消示例
async function cancellableOperation(signal: AbortSignal) {
  return new Promise((resolve, reject) => {
    // 监听取消信号
    signal.addEventListener('abort', () => {
      reject(new Error('操作已取消'));
    });
    
    // 模拟异步操作
    const timer = setTimeout(() => {
      resolve('操作完成');
    }, 5000);
    
    // 如果被取消,清理资源
    signal.addEventListener('abort', () => {
      clearTimeout(timer);
    });
  });
}

// 使用示例
const controller = new AbortController();
const { signal } = controller;

// 启动异步操作
cancellableOperation(signal)
  .then(result => console.log(result))
  .catch(error => console.log(error.message)); // 操作已取消

// 500ms后取消操作
setTimeout(() => controller.abort(), 500);

5.4 异步代码的单元测试

使用OpenHarmony的测试框架进行异步代码测试:

import { describe, it, expect, done } from '@ohos/hypium';
import { fetchData } from '../main/asyncOperation';

describe('异步操作测试', () => {
  it('测试成功路径', async (done: Function) => {
    try {
      const result = await fetchData('https://api.example.com/test');
      expect(result).not.toBeNull();
      expect(result.code).toBe(0);
      done();
    } catch (error) {
      done(error); // 测试失败
    }
  });
  
  it('测试超时场景', async (done: Function) => {
    jest.useFakeTimers();
    
    try {
      const promise = fetchData('https://api.example.com/slow');
      jest.advanceTimersByTime(6000); // 快进时间
      await promise;
      done(new Error('应该超时但没有超时'));
    } catch (error) {
      expect(error.message).toContain('超时');
      done();
    } finally {
      jest.useRealTimers();
    }
  });
});

6. 常见问题与解决方案

6.1 忘记处理错误

问题:忽略异步操作中的错误处理,可能导致应用崩溃或数据不一致。

解决方案:始终为异步操作添加错误处理,使用try/catch或.catch()。

// 不好的做法
async function badErrorHandling() {
  const data = await fetchData(); // 可能抛出错误但未处理
  process(data);
}

// 好的做法
async function goodErrorHandling() {
  try {
    const data = await fetchData();
    process(data);
  } catch (error) {
    console.error("处理错误:", error);
    showErrorUI(error.message); // 向用户展示错误信息
  }
}

6.2 滥用Async函数

问题:将所有函数都声明为async,即使它们不包含异步操作。

解决方案:只有当函数内部使用await或需要返回Promise时,才使用async关键字。

// 不好的做法
async function syncOperation() {
  return "结果"; // 返回的是Promise<string>而不是string
}

// 好的做法
function syncOperation() {
  return "结果"; // 返回string
}

6.3 内存泄漏

问题:异步操作完成前组件已销毁,导致回调函数中的引用无法释放。

解决方案:使用生命周期管理和取消机制。

// 组件中的异步操作管理
import { BusinessError } from '@ohos.base';

class MyComponent extends Component {
  private abortController: AbortController | null = null;
  
  aboutToAppear() {
    this.abortController = new AbortController();
    this.loadData();
  }
  
  aboutToDisappear() {
    // 组件销毁时取消异步操作
    this.abortController?.abort();
  }
  
  private async loadData() {
    try {
      const data = await fetchData({ 
        signal: this.abortController?.signal 
      });
      this.updateUI(data);
    } catch (error) {
      if (!(error instanceof BusinessError) || error.code !== 1001) { // 1001假设是取消错误码
        console.error("加载数据失败:", error);
      }
    }
  }
}

7. 总结与展望

7.1 内容回顾

本文详细介绍了OpenHarmony中的异步编程模型,重点讲解了Promise和Async/Await的使用方法,包括:

  • Promise的状态机制和常用方法
  • Async/Await的语法和错误处理
  • OpenHarmony API中的异步应用
  • 最佳实践和性能优化技巧
  • 常见问题和解决方案

7.2 异步编程模式对比

模式优点缺点适用场景
回调函数简单直接,兼容性好回调地狱,错误处理繁琐简单异步场景,兼容性要求高
Promise链式调用,错误集中处理仍有回调,复杂流程可读性差中等复杂度异步流程
Async/Await代码清晰,接近同步风格,错误处理直观需要ES2017支持所有异步场景,特别是复杂流程

7.3 未来趋势

随着OpenHarmony的不断发展,异步编程模型也在持续演进。未来可能会看到:

  • 更完善的异步迭代器支持
  • Top-level await的广泛应用
  • 响应式编程模型(如RxJS)的集成
  • 更智能的编译器优化异步代码

掌握异步编程是OpenHarmony应用开发的必备技能。通过合理运用Promise和Async/Await,结合本文介绍的最佳实践,你可以编写出更高效、更健壮、更易维护的OpenHarmony应用。

附录:异步编程检查清单

在编写异步代码时,可参考以下检查清单:

  •  是否避免了不必要的异步操作
  •  是否正确处理了所有可能的错误
  •  是否合理使用并行执行提高性能
  •  是否避免了"Promise地狱"(过度嵌套)
  •  是否正确清理了异步操作的资源
  •  是否考虑了操作取消的场景
  •  是否为长时间运行的异步操作提供了进度反馈
  •  是否对异步代码进行了充分的测试

【免费下载链接】docs OpenHarmony documentation | OpenHarmony开发者文档 【免费下载链接】docs 项目地址: https://gitcode.com/openharmony/docs

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值