带你重学ES6 | Async和Await

2,255 阅读4分钟

async 是 ES7 提出的新特性,说白了就是 Generator 的语法糖。 既然是语法糖,那我们首先说一下它的改进之处。

1、async 对 Generator 的改进

1.1、写法改进

Generator函数;
function* foo() {
  yield "b";
}
Async函数;
async function foo() {
  await "b";
}

对比发现,async 函数在写法上,是将 Generator 函数的星号换成了 async 关键词,yield 关键词换成了 await。

1.2、 内置执行器

Generator 函数的执行必须依靠执行器,而 async 函数自带执行器。所以 async 函数不用像 Generator 函数一样要用 next 方法才会执行,完全可以跟普通函数一样。

1.3、 更好的实用性

co 模块约定,yield 命令后面只能是 Thunk 函数或 Promise 对象,而 async 函数的 await 命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。

1.4、 返回值为 Promise

async 函数返回的是一个 Promise 对象,可以试用 then 方法,不像 Generator 函数返回的是一个 Iterator 对象。

2、async 基本用法

async 函数返回一个 Promise 对象,可以使用 then 方法添加回调函数。当函数执行的时候,一旦遇到 await 就会先返回,等到异步操作完成,再接着执行函数体内后面的语句,并且 await 必须要在 async 函数中,不然就会报错。

async function foo() {
  let result = await "b";
  return result;
}
foo().then((value) => console.log(value)); // b

上述可以看出,async 函数中 return 语句返回的值,会成为 then 回调函数的参数。 当 async 函数中抛出错误时,会作为 catch 函数的参数传入。

async function foo() {
  throw new Error("出错");
}
foo().catch((err) => console.log(err)); // Error: 出错

3、await 表达式

通常来说 await 后边大部分都是 Promise 对象,当时 Promise 对象时,返回的是 Promise 对象 resolved 状态下的结果,如果是基本数据类型时,就是直接返回该结果。

async function foo() {
  let result = await new Promise((resolve) => resolve(1));
  return result;
}
foo().then((value) => console.log(value)); // 1

当 await 后边是一个 thenable 对象是,会被当做是 Promise 对象一样处理。

let thenable = {
  name: "Jack",
  then: (resolve) => resolve("2"),
};
async function foo() {
  let result = await thenable;
  return result;
}
foo().then((value) => console.log(value)); // 2

await 后面的 Promise 对象出现错误时:

async function foo() {
  await Promise.reject("出错了");
  await Promise.resolve("1");
}
foo()
  .then((value) => console.log(value))
  .catch((err) => console.log(err)); // 出错了

当有多个 await 时,只要其中一个 await 后的 Promise 报错,那该表达式之后的所有语句将不再执行。如果想要执行之后的语句的话,可以使用 try...catch...

async function foo() {
  try {
    await Promise.reject("出错了");
  } catch (err) {
    console.log(err); // 出错了
  }
  return await Promise.resolve("1");
}
foo()
  .then((value) => console.log(value)) // 1
  .catch((err) => console.log(err));

除此之外还有一种方法:

async function foo() {
  await Promise.reject("出错了").catch((err) => console.log(err)); // 出错了
  return await Promise.resolve("1");
}
foo()
  .then((value) => console.log(value)) // 1
  .catch((err) => console.log(err));

因为 catch 抓的是它之前的错误。 值得注意的是,如果有多个await时,这几个await并不是同时触发,而是继发,即上一条await后的Promise成功后再触发下一条await,如果想同时触发的话,可选用Promise.all方法。

async function foo() {
  let [a, b] = await Promise.all([new Promise(resolve=>resolve(1)), new Promise(resolve=>resolve(2))]);
  return [a, b];
}

后语

相关文章:

觉得还可以的,麻烦走的时候能给点个赞,大家一起学习和探讨!

还可以关注我的博客希望能给我的github上点个Start,小伙伴们一定会发现一个问题,我的所有用户名几乎都与番茄有关,因为我真的很喜欢吃番茄❤️!!!

想跟车不迷路的小伙还希望可以关注公众号 前端老番茄 或者扫一扫下面的二维码👇👇👇。

我是一个编程界的小学生,您的鼓励是我不断前进的动力,😄希望能一起加油前进。

本文使用 mdnice 排版