码字,杂谈

真丶深入理解JavaScript异步编程(三):async / await

这一篇内容比较短,介绍新增的语法糖。其实也不算新了。。。

async / await

这两个写法是 ES6 新加的特性,这让我们的代码更加简单明了。但是这并不是什么新技术,只是一个语法糖而已,它的本质还是 Promise。

await

我个人理解,await 是这两个语法糖的重点。它具有以下特点:

  • 它后面需要跟一个 Promise,如果是一个值,则会自动包裹成一个 Promise
  • 它需要在异步函数内部使用,也就是函数必须使用 async 修饰。

await 相当于前面提到过的 then,使用 await 等待其后 Promise 的结果,只有获取了结果,程序才会继续执行,否则会一直等待。

async function get() {
  let name = await new Promise(resolve => {
    setTimeout(() => resolve("jeremyjone"), 1000);
  });
  console.log(name);
}

get(); // 等待1秒后,打印:jeremyjone

async

先来看一下 async 的写法:

async function get() {
  return "jeremyjone";
}

此时 get 方法摇身一变,成了一个异步函数,它本质上返回一个 Promise,我们在使用的时候仍然可以通过 then 来使用。这也就是为什么 await 需要在 async 修饰的函数中,它们相互又可以成为一个链式操作:

// 接上例
get().then(v => console.log(v)); // jeremyjone

// 或者使用 await
let r = await get();
console.log(r); // jeremyjone

此时的 get 方法就相当于:

function get() {
  return new Promise(resolve => {
    resolve("jeremyjone");
  });
}

这就是两个异步语法糖的用法。

捕获异常

捕获 async 的异常

因为 async 方法返回的是一个 Promise,所以和普通 Promise 的异常捕获一样,在调用时通过 .catch() 即可捕获。

async function get() {
  return "jeremyjone";
}

// 调用
get()
  .then(v => console.log(v))
  .catch(err => console.log(err));

这是不存在任何问题的。

捕获 await 的异常

最简单的方式,我们可以通过 try...catch 直接捕获 await 语句的异常:

async function get() {
  try {
    let name = await new Promise(resolve => {
      setTimeout(() => resolve("jeremyjone"), 1000);
    });
    console.log(name);
  } catch (error) {
    console.log(error);
  }
}

但是这样不够优雅,结合我之前写过的内容,可以使用大神封装好的库。但是我又不想安装,所以直接自己封装成函数。

它的思路是这样的:写一个方法,包装所有的 Promise,让所有 Promise 同时返回成功的数据和异常的错误,然后由使用者抉择如何使用它们。如果成功,那么异常为 null;如果失败,那么数据则为 undefined

不得不说,大神的思路简单清晰,而且代码非常简单,易于理解。

PS:有时候我们与大神差的真的只是思路。[偷笑]

function to(promise, errExt) {
  return promise
    .then(data => [null, data])
    .catch(err => {
      if (errExt) {
        Object.assign(err, errExt);
      }
      return [err, undefined];
    });
}

多么的清晰。将这个函数包装到所有需要使用的 Promise,现在 await 返回的将是一个具有两个参数的数组,第一个值是异常,第二个值是数据,随便使用。

async function get() {
  const [err, name] = await to(
    new Promise(resolve => {
      setTimeout(() => resolve("jeremyjone"), 1000);
    })
  );
  console.log(name);
}

是不是优雅了很多~~~

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注