鸿蒙开发中 Promise的理解

本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新

一、Promise 就像「外卖订单」

想象你点了一份外卖:

  1. 下单时刻(Pending)

    • 你付完钱,订单状态变成「制作中」
    • 这时候你既没拿到饭,也没失败
  2. 结果到来

    • 成功(Fulfilled):外卖员把饭送到你手里
    • 失败(Rejected):餐厅打电话说「食材没了,退钱吧」
  3. 你的应对

    • 成功时:打开包装开始吃(.then()
    • 失败时:换一家店重新点(.catch()
// 用代码表示就是:
const 外卖订单 = new Promise((成功, 失败) => {
  if (餐厅有食材) {
    成功("宫保鸡丁饭"); 
  } else {
    失败("食材缺货");
  }
});

外卖订单
  .then(饭 => console.log("开吃:" + 饭))
  .catch(原因 => console.log("换一家,因为:" + 原因));

二、鸿蒙中为什么必须用 Promise?

1. 所有耗时操作都是异步的

以下操作必须通过 Promise 处理:

  • 读取文件
  • 网络请求
  • 数据库查询
  • 调用硬件(如摄像头)
// 鸿蒙文件读取示例
import fs from '@ohos.file.fs';

// 没有Promise的写法(错误!)
const file = fs.readFileSync('/data/test.txt'); // ❌ 同步读取会卡死界面

// 正确写法 ✅
fs.readFile('/data/test.txt').then(file => {
  console.log("文件内容:", file);
});
2. 避免「回调地狱」

对比两种写法:

// 回调地狱写法(难以维护)
请求1(参数, () => {
  请求2(参数, () => {
    请求3(参数, () => {
      // 更多嵌套...
    });
  });
});

// Promise链式调用(清晰)
请求1(参数)
  .then(结果 => 请求2(参数))
  .then(结果 => 请求3(参数))
  .then(结果 => console.log("完成!"));

三、自己实现Promise的极简版

用一个简单的setTimeout模拟鸿蒙的异步操作:

class 我的Promise {
  private 状态 = '等待'; // '等待' | '成功' | '失败'
  private 结果: any;
  private 回调队列: Function[] = [];

  constructor(执行函数: (成功, 失败) => void) {
    const 成功 = (值) => {
      if (this.状态 !== '等待') return;
      this.状态 = '成功';
      this.结果 = 值;
      this.执行回调();
    };
    
    const 失败 = (原因) => {
      if (this.状态 !== '等待') return;
      this.状态 = '失败';
      this.结果 = 原因;
      this.执行回调();
    };

    try {
      执行函数(成功, 失败);
    } catch (错误) {
      失败(错误);
    }
  }

  then(成功回调?: Function, 失败回调?: Function) {
    return new 我的Promise((resolve, reject) => {
      this.回调队列.push(() => {
        try {
          if (this.状态 === '成功') {
            const 新结果 = 成功回调?.(this.结果) ?? this.结果;
            resolve(新结果);
          } else {
            const 新结果 = 失败回调?.(this.结果) ?? this.结果;
            reject(新结果);
          }
        } catch (错误) {
          reject(错误);
        }
      });
      
      if (this.状态 !== '等待') this.执行回调();
    });
  }

  private 执行回调() {
    // 模拟鸿蒙的异步调度
    setTimeout(() => {
      this.回调队列.forEach(回调 => 回调());
      this.回调队列 = [];
    }, 0);
  }
}

// 使用示例
const 示例任务 = new 我的Promise((成功) => {
  setTimeout(() => 成功("异步操作完成"), 1000);
});

示例任务.then(结果 => console.log(结果)); // 1秒后输出

四、开发中的实际应用

场景:同时加载用户数据和配置
import http from '@ohos.net.http';
import preferences from '@ohos.data.preferences';

// 1. 封装网络请求为Promise
function 获取用户信息(userId: string): Promise<any> {
  return new Promise((resolve, reject) => {
    const request = http.createHttp();
    request.request(
      `https://api.example.com/users/${userId}`,
      {
        method: 'GET',
        connectTimeout: 60000,
      },
      (err, data) => err ? reject(err) : resolve(JSON.parse(data.result))
    );
  });
}

// 2. 封装本地存储为Promise
function 读取配置(): Promise<string> {
  return new Promise((resolve, reject) => {
    preferences.getPreferences('config', (err, prefs) => {
      if (err) return reject(err);
      prefs.get('theme', 'default', (err, value) => {
        err ? reject(err) : resolve(value);
      });
    });
  });
}

// 3. 合并多个异步操作
Promise.all([获取用户信息('123'), 读取配置()])
  .then(([用户数据, 主题配置]) => {
    console.log(`欢迎${用户数据.name},当前主题:${主题配置}`);
  })
  .catch(错误 => {
    console.error('初始化失败:', 错误);
  });

五、常见问题

1: 为什么不能直接用回调函数?

A: 当多个异步操作需要顺序执行时,回调会导致「金字塔缩进」:

获取用户(id, 用户 => {
  获取订单(用户.id, 订单 => {
    获取商品(订单.id, 商品 => {
      // 更多嵌套...
    });
  });
});

而Promise可以通过链式调用保持代码扁平:

获取用户(id)
  .then(用户 => 获取订单(用户.id))
  .then(订单 => 获取商品(订单.id))
  .then(商品 => console.log(商品));
2: async/await 和 Promise 什么关系?

A: async/await 是Promise的语法糖:

// 这两种写法完全等价
async function 示例1() {
  const data = await 获取数据();
  console.log(data);
}

function 示例2() {
  获取数据().then(data => console.log(data));
}
3: 为什么鸿蒙的API都返回Promise?

A: 因为JavaScript是单线程的,如果同步执行耗时操作(如读取大文件),界面会完全卡住。Promise保证了所有耗时操作都不会阻塞主线程。

六、总结

  1. Promise是什么 一个表示「未来才会完成的操作」的容器,有三种状态: ⏳ Pending(进行中) → ✅ Fulfilled(成功) / ❌ Rejected(失败)

  2. 鸿蒙中怎么用

    • 所有耗时API(文件、网络、数据库)都返回Promise
    • .then()处理成功,.catch()处理失败
  3. 为什么需要它

    • 避免界面卡顿(异步非阻塞)
    • 解决回调地狱(链式调用)
    • 统一异步操作标准(所有鸿蒙API都遵循)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值