HarmonyOs DevEco Studio小技巧24--异步编程(Promises、async/await)

异步编程调用后耗时,不阻塞代码继续执行,将来完成后,触发回调函数传递结果

异步编程的范畴:

  1. 网络请求(如使用 fetch 或 XMLHttpRequest 发送 HTTP 请求获取数据)。
  2. 文件读写操作(读取或写入本地文件)。
  3. 数据库操作(查询、插入、更新、删除数据)。
  4. 定时器函数(如 setTimeout 和 setInterval)。
  5. 事件处理(例如用户的点击、鼠标移动等事件)。

console.log('1 -----> ', 1)
setTimeout(() => {
  console.log('2 -----> ', 2)
}, 100)
console.log('3 -----> ', 3)
setTimeout(() => {
  console.log('4 -----> ', 4)
}, 0)
console.log('5 -----> ', 5)

猜一下 ,控制台打印出来的是啥 ??

基本概念

首先,我们需要明白async/awaitPromise都是JavaScript中处理异步操作的API。

  • Promise: 是一种代表了某个异步操作最终完成(或失败)及其结果值的对象。
  • async/await: 是基于Promise的语法糖,它允许我们以更同步的方式编写异步代码。

Promises(承诺)

承诺:承诺就像是一座桥梁🌉 连接着你和别人,或者连接着现在的你和未来的你。

 

它是你对别人的一种保证,也是你对自己的一种约束。当你做出承诺时,就像是在说:“我会尽我所能,让这件事成真!”,但是我们无法保证他一定会是真的。就比如说,

承诺十月底份减肥十斤------------------------------------------------------------------>Promise 

那现在承诺的状态就是进行中,因为十月份还没有过--------------------------->pending

假设十一月份到了,我确实瘦了十斤,那么这个承诺就是成功的------------>fulfilled

没有瘦十斤,那么承诺就是失败的--------------------------------------------------->rejected

Promise 是 JavaScript 中处理异步操作的一种常见方式。Promise 有三种状态:

pending(进行中):初始状态,既没有被兑现,也没有被拒绝

fulfilled(已成功):意味着操作成功完成

rejected(已失败): 意味着操作失败

状态有一些特性:

  • 只能通过执行函数修改
  • 外部无法读取
  • 外部无法修改

1.创建一个 Promise 对象:

   const myPromise = new Promise((resolve, reject) => {
     // 异步操作
     if (/* 异步操作成功的条件 */) {
       resolve('成功的值'); // 成功时调用 resolve 并传递结果
     } else {
       reject('失败的原因'); // 失败时调用 reject 并传递错误信息
     }
   });
  1. 使用 then 方法处理成功的结果:
       myPromise.then(result => {
         console.log(result); // 处理成功返回的结果
       });
  2. 使用 catch 方法处理失败的情况:
    // error 需要指定类型,ArkTS推断不出来
    myPromise.catch((error:string) => {
         console.error(error); // 处理失败时的错误信息
       });
  • 举个例子
  • 定义了一个名为 asyncOperation 的函数,该函数返回一个 Promise 对象,并且明确指定这个 Promise 成功时解析的值的类型为字符串。
function asyncOperation(): Promise<string> { 
  return new Promise<string>((resolve, reject) => { 
    // 模拟异步操作
    setTimeout(() => {
      if (Math.random() > 0.5) {
        resolve('操作成功');
      } else {
        reject('操作失败');
      }
    }, 1000);
  });
}

asyncOperation()
  .then(result => console.log(result)) //随机数大于0.5返回操作成功
  .catch((error:string) => console.error(error)); //随机数小于0.5返回操作失败
  • 调用 asyncOperation 函数来执行其中的异步操作。
  • 使用 then 方法来处理 Promise 成功时的情况。当异步操作成功(即随机数大于 0.5),resolve 被调用,then 中的回调函数会被执行,将成功的结果(字符串 '操作成功')传递给 result 参数,并通过 console.log 打印出来。
  • 使用 catch 方法来处理 Promise 失败时的情况。当异步操作失败(即随机数小于 0.5),reject 被调用,catch 中的回调函数会被执行,将失败的信息(字符串 '操作失败')传递给 error 参数,并通过 console.error 打印错误信息。

2. Promise的链式写法

Promise 的链式写法允许在一个 Promise 的 then 方法中返回另一个 Promise,从而形成链式的调用

基本写法: 

new Promise((resolve, reject) => {
  // 异步操作
  if (/* 成功条件 */) {
    resolve('成功的值');
  } else {
    reject('失败的原因');
  }
})
.then(result => {
  // 对成功结果进行处理,返回一个新的 Promise 或值
  return new Promise((resolve, reject) => {
    // 新的异步操作或处理逻辑
    if (/* 新的成功条件 */) {
      resolve('新的成功结果');
    } else {
      reject('新的失败原因');
    }
  });
})
.then(result => {
  // 继续处理上一个 then 返回的结果
  // 可以继续返回新的 Promise 以形成更长的链
})
.catch(error => {
  // 处理任何一个环节的失败情况
  console.error(error);
});

在链式写法中:

  • 每个 then 方法接收上一个 then 或 resolve 传递的值,并可以返回一个新的 Promise 或者直接返回一个值。
  • catch 方法用于捕获整个链中任何一个环节出现的错误。

举个例子

function createRandomPromise(delay: number, successMessage: string, failureMessage: string): Promise<string> {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (Math.random() > 0.5) {
        resolve(successMessage);
      } else {
        reject(failureMessage);
      }
    }, delay);
  });
}


createRandomPromise(1000, '操作成功', '操作失败')
  .then(result => {
    console.log(result);
    return createRandomPromise(1500, '第二次操作成功', '第二次操作失败');
  })
  .then(result => {
    console.log(result);
    return createRandomPromise(2000, '第三次操作成功', '第三次操作失败');
  })
  .then(result => {
    console.log(result);
  })
  .catch((error: string) => {
    console.error(error);
  });

成功 fulfilled

失败 rejected

这种方式可以有效地处理异步操作,但当涉及到多个异步操作时,代码可能会变得复杂和难以阅读,这通常被称为“回调地狱”。

3. Promise 的静态方法:

Promise.all([promises])
  • 接受一个可迭代对象(如数组),其中的元素都是 Promise 实例。当所有的 Promise 都成功时,返回一个新的 Promise,其结果是一个数组,包含所有输入 Promise 的成功结果,按照输入的顺序排列。
    const promise1 = Promise.resolve(3);
    const promise2 = 42;
    const promise3 = new Promise((resolve, reject) => {
      setTimeout(resolve, 5000, 'foo');
    }) as Promise<string>;
    
    //这里调换了23的顺序
    Promise.all([promise1, promise3,promise2])
      .then((values) => {
      console.log(values.toString())})
      .catch((error:string) => {
      console.log(error)});
    //全是成功的,所以打印出来的数据 3 foo 42
  • 快速失败机制:如果有任何一个 Promise 失败,则整个 Promise.all 失败,返回的 Promise 会立即被拒绝,并返回第一个失败 Promise 的错误原因。                                  (不管有几个Promise,只要有一个失败了,其他的Promise就不会在执行了)
    const promise1 = Promise.resolve(3);
    const promise2 = 42;
    const promise3 = new Promise((resolve, reject) => {
      setTimeout(reject, 5000, 'foo');
    }) as Promise<string>;
    
    Promise.all([promise1, promise3,promise2])
      .then((values) => {
      console.log(values.toString())})
      .catch((error:string) => {
      console.log(error)});
    //因为3是失败的,所以只返回了 foo
Promise.allSettled([promises])
  • 接受一个可迭代对象,其中的元素都是 Promise 实例。
  • 返回一个新的 Promise,当所有输入的 Promise 都已完成(不管是成功完成还是失败完成)时,这个新的 Promise 完成。其结果是一个数组,每个元素都描述对应的输入 Promise 的完成状态和结果(如果成功则是值,如果失败则是错误原因)。
    const promise1 = Promise.resolve(3);
    const promise2 = new Promise((resolve, reject) => reject('出错啦!')) as Promise<string>;
    
    Promise.allSettled([promise1, promise2]).then((results) => {
      results.forEach((result) => {
        if (result.status === 'fulfilled') {
          console.log(result.value.toString());
        } else {
          console.error(result.reason);
        }
      });
    });
    
    //返回了 3 和 出错啦!
Promise.race()
  • 接受一个可迭代对象,其中的元素都是 Promise 实例。
  • 返回一个新的 Promise,只要输入的 Promise 中有一个完成(不管是成功完成还是失败完成),就采用第一个完成的 Promise 的结果。
    const promise1 = new Promise((resolve, reject) => {
      setTimeout(resolve, 500, 'one');
    }) as Promise<string>;
    const promise2 = new Promise((resolve, reject) => {
      setTimeout(resolve, 100, 'two');
    }) as Promise<string>;
    const promise3 = new Promise((resolve, reject) => {
      setTimeout(resolve, 1, 'three');
    }) as Promise<string>;
    
    Promise.race([promise1, promise2,promise3])
      .then((value) => {
        console.log(value);
      })
      .catch((error: string) => {
        console.log(error);
      })
    
Promise.resolve()
  • 将给定的值转换为一个已解决(resolved)的 Promise 。如果给定的值本身就是一个 Promise,则直接返回它。
    const resolvedPromise = Promise.resolve('直接成功');
    resolvedPromise.then((value) => {
      console.log(value);
    });
Promise.reject()
  • 创建一个已拒绝(rejected)的 Promise ,并带有指定的拒绝原因。
const rejectedPromise = Promise.reject('直接失败');
rejectedPromise.catch((reason:string) => {
  console.error(reason);
});

async函数和 await

async/await 是一种非常强大和直观的方法。它是在ES2017中引入的,使得异步代码的阅读和编写更像是传统的同步代码,提高了代码的可读性和可维护性。

async关键字用于声明一个异步函数,而await关键字则用于等待一个Promise的解决(fulfill)或拒绝(reject)。

async 函数:

  • 一个函数前面加上 async 关键字,就变成了 async 函数。
  • async 函数总是返回一个 Promise
  • 异步函数可以包含 await 表达式,以等待其他异步操作完成。
    async function fetchUserData(userId: number) {
      const response = await http
        .createHttp()
        .request(`https://example.com/api/user/${userId}`) ;
      const data = response.result as User;
      return data;
    }
    

await 关键字:

  • await 只能在 async 函数内部使用,它用于等待一个Promise解决为其值。
  • await 将暂停函数的执行,直到等待的Promise完成(无论成功或失败)并返回结果。
  • 如果 Promise 被拒绝(即抛出错误),那么 await 表达式会抛出异常,需要在 async 函数中使用 try/catch 块来处理错误。
    async function getData() {
      try {
        const response = await http.createHttp().request('https://example.com/data');
        const data =  response.result;
        return data;
      } catch (error) {
        console.error('获取数据时出错:', error);
        return null;
      }
    }

    await关键字其实很简单,js运行在碰到await关键字时,会记录在哪里暂停执行。等到await右边的值可以使用了,就是处理完回调了,js会向消息列对中推送一个任务,这个任务会恢复异步函数的执行。这样的话,即使await后面跟着一个立即可用的值,函数的其余部分也会被异步求值。

        async function fun01(){
            console.log(await Promise.resolve('第一名'));
        }
        async function fun02(){
            console.log(await '第二名');
        }
        async function fun03(){
            console.log('第三名');
        }
        fun01();
        fun02();
        fun03();

    打印结果是 3 1 2

  • 注意事项

  • await不能单独使用,必须和async配对使用
  • async要加在离await最近的函数,表示一对
  • async修饰的函数,返回值类型会自动变为Promise<T>
  • await只能拿到成功的结果,无法拿到失败的结果
  • try-catch可以用来捕获任意的异常,并不仅仅局限于 async 函数

在JavaScript中,异步调用一直是一个重要的话题。许多开发者已经习惯使用Promise、回调函数等方式来处理异步代码。但是,使用async/await语法可以让异步代码更加简洁易读。 async/await是ES2017(ES8)的标准,它们允许我们以同步的方式编写异步代码。async/await基于Promises,它们提供了一种更容易理解和使用的方式来解决异步交互。 1. async 函数 要使用 async/await 异步调用,必须先创建一个async 函数, 像这样: ```javascript async function myAsyncFunction() { // code goes here } ``` async 函数是在定义时就立即执行的。这可以让我们确保异步代码在异步执行之前被定义。 2. await 关键字 在async函数中,调用异步操作时需要await关键字。它可以使函数停止执行,等待异步操作完成,然后返回异步操作的结果。 例如,可以等待一个Promise对象完整处理后返回结果,像这样: ```javascript async function myFunction() { const result = await myAsyncOperation(); console.log(result); } ``` 在这个例子里,myAsyncOperation()可能需要很长时间才能完成。await确保在异步操作返回之前,不会执行代码的后续部分。当操作完成时,async函数才会继续执行。 3. 错误处理 回调函数中的错误处理有时非常麻烦。但是,使用async /await,可以使用try...catch块十分方便地处理错误。 例如,如果await的异步函数失败,可以使用try/catch语句捕获该错误。 ```javascript async function myFunction() { try { const result = await myAsyncOperation(); console.log(result); } catch (error) { console.error('There was a problem with the async operation:', error); } } ``` 在这个例子里,如果myAsyncOperation 函数中有一个错误,将控制台记录相应错误信息。 总而言之,async/await 语法是一种很好的方式来处理异步操作。不仅它可以使异步代码更加简洁易读,同时也提供了错误处理和其他便利功能,通过这种方式,我们可以更加有效地管理我们的异步代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值