详解async-await的用法

493 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第30天,点击查看活动详情

async-await

async-await是ECMA17提出来的基于promise对象的语法糖。可以让异步操作更加地明了。通过使用async关键字将函数标记为异步函数(也就是promise对象的函数),然后在异步函数中调用其他的异步函数,这时是使用await语法调用这个异步函数。

await会等待promise完成之后直接返回最终的结果。

通俗地讲就是async是用来定义异步函数的,而await必须用在async定义的异步函数中,用于等待一个 Promise兑现并获取它兑现之后的值。

1. async关键字

  1. 定义异步函数
  2. 返回类型为Promise的对象
  3. 无阻塞,不等待,在没有await的情况下执行async函数,它会立即执行,返回一个Promise对象,并且绝对不会阻塞后面的语句,这和普通返回Promise对象的函数一样。
async function fun() {
  return Promise.resolve('好好学习!');
}

2. await关键字

  1. 只能在async函数内部使用
  2. await关键字紧跟Promise对象
  3. 后面可以写同步代码
  4. await是async wait的意思: wait的是resolve()的消息,并把数据data返回,比如下面代码中,当Promise对象由Pending变为Resolved的时候,就执行await这个语句,然后再顺序执行下面的语句。这点有点类似于同步代码的执行。
  5. await对于失败消息是不会处理的,因此一般采用下面方式处理
  • 让await后面的Promise对象自己catch
  • 让外面的async函数返回的Promise对象统一catch
  • 放在try...catch中
// 让await后面的Promise对象自己catch
const response = await promisedFunction().catch((err) => {
  console.error(err);
  return "default response";
});

// 让外面的async函数返回的Promise对象统一catch
async function fun() {
  return Promise.resolve('好好学习!');
};
fun.catch((err) => {
  console.error(err);
});
// 放在try...catch中
async function f4() {
  try {
    const z = await Promise.reject(30);
  } catch (e) {
    console.error(e); // 30
  }
}

async-await在使用时需要注意的坑

1. async中的用到两个await函数,这样第一个函数会影响到后面函数的执行

async function fun() {
  const a = await fetch('http://.../1');
  const b = await fetch('http://.../2');
}

这时第一个await函数会阻塞第二个await函数的执行,也就是说第一个await函数没有执行完的话是不会执行第二个await函数的。

这时最高效地做法是将所有promise用promise.all组合起来,然后再使用await。

async function fun() {
  const promiseA = fetch('http://.../1');
  const promiseB = fetch('http://.../2');

  const [a, b] = await Promise.all([promiseA, promiseB]);
}

2. 在循环中执行异步操作,是不能直接调用forEach或者map这一类方法

async function fun() {
  [1, 2, 3].forEach(async (i) => {
    await  asynFunc();
  });
  console.log('I done');
}

在上述函数中,即使我们写了await,但是它并不会暂停等到所有异步操作都执行完成,而是立即返回forEach的执行结果。

如果我们想要在循环中执行异步操作应该使用传统的for循环

async function fun() {
  let arr = [1, 2, 3];
  for ( let i = 0; i < arr.length; i++) {
    await  asynFunc();
  }
  console.log('I done');
}

或者使用for await关键字,这时for循环依然会等到所有的异步操作都完成之后才继续向后执行。

async function fun() {
  let arr = [1, 2, 3];
  for await ( let i of arr) {
    asynFunc();
  }
  console.log('I done');
}

3. 不能在全局或者普通函数中直接使用await关键字

await asynFunc();

await只能使用在async异步函数中,如果我们想要在最外层中使用await,需要先定义一个异步函数,然后在函数体中使用它。

async function fun() {
  await asynFunc();
}