学会使用前端async和await

这是我参与8月更文挑战的第17天,活动详情查看:8月更文挑战

前言

之前我有分享过Promise.then()已经可以很好的解决回调地狱问题,这篇我分享的async和await,虽然也使用到了Promise但是却减少了Promise的then处理使得整个异步请求代码清爽了许多。

async和await是ES7的语法,它们是基于promise的语法糖,使异步代码更易于编写和阅读。通过使用它们,异步代码看起来更像是老式同步代码。

async关键字

用来声明一个函数为异步函数,如果这个函数有返回值,它能保证函数的返回值为 promise,而不是直接返回值。

let hello = async () => { return "Hello" };
hello().then((value) => console.log(value)) //Hello
复制代码

这里大家就会有疑问了,既然async返回的是promise,那不也用then来处理回调的吗?

用then来出来当然也没问题,但是我们有更好的await。

await关键字

await 只在异步函数里面才起作用,它可以放在任何异步的,基于 promise 的函数之前。它会暂停代码在该行上,直到 promise 完成,然后返回结果值。在暂停的同时,其他正在等待执行的代码就有机会执行了。

您可以在调用任何返回Promise的函数时使用 await,包括Web API函数。

我们拿使用promise.then和使用async/await的代码做下对比:

我们默认fetch是个返回promise的异步函数

promise.then:

fetch('coffee.jpg')
.then(response => response.blob())
.then(myBlob => {
  let objectURL = URL.createObjectURL(myBlob);
  let image = document.createElement('img');
  image.src = objectURL;
  document.body.appendChild(image);
})
.catch(e => {
  console.log('There has been a problem with your fetch operation: ' + e.message);
});
复制代码

async/await:

async function myFetch() {
  let response = await fetch('coffee.jpg');
  let myBlob = await response.blob();

  let objectURL = URL.createObjectURL(myBlob);
  let image = document.createElement('img');
  image.src = objectURL;
  document.body.appendChild(image);
}

myFetch()
.catch(e => {
  console.log('There has been a problem with your fetch operation: ' + e.message);
});
复制代码

我们可以直观的看到后者去除了到处都是 .then() 代码块使得代码更加好看简洁

async/await的缺陷

Async/await 让你的代码看起来是同步的,在某种程度上,也使得它的行为更加地同步。 await 关键字会阻塞其后的代码,直到promise完成,就像执行同步操作一样。它确实可以允许其他任务在此期间继续运行,但您自己的代码被阻塞。

这意味着您的代码可能会因为大量await的promises相继发生而变慢。每个await都会等待前一个完成,而你实际想要的是所有的这些promises同时开始处理(就像我们没有使用async/await时那样)。

有一种模式可以缓解这个问题——通过将 Promise 对象存储在变量中来同时开始它们,然后等待它们全部执行完毕。让我们看一些证明这个概念的例子。

使用setTimeout() 调用伪造异步进程:

function timeoutPromise(interval) {
  return new Promise((resolve, reject) => {
    setTimeout(function(){
      resolve("done");
    }, interval);
  });
};
复制代码

然后每个包含一个 timeTest() 异步函数,等待三个 timeoutPromise() 调用

async function timeTest() {
  await timeoutPromise(3000);
  await timeoutPromise(3000);
  await timeoutPromise(3000);
}
复制代码

在这里,我们直接等待所有三个timeoutPromise()调用,使每个调用3秒钟。后续的每一个都被迫等到最后一个完成 – 如果你运行第一个例子,你会看到弹出框报告的总运行时间大约为9秒。

async function timeTest() {
  const timeoutPromise1 = timeoutPromise(3000);
  const timeoutPromise2 = timeoutPromise(3000);
  const timeoutPromise3 = timeoutPromise(3000);

  await timeoutPromise1;
  await timeoutPromise2;
  await timeoutPromise3;
}
复制代码

在这里,我们将三个Promise对象存储在变量中,这样可以同时启动它们关联的进程。

接下来,我们等待他们的结果 – 因为promise都在基本上同时开始处理,promise将同时完成;当您运行第二个示例时,您将看到弹出框报告总运行时间仅超过3秒!

总结

async/await提供了一种很好的,简化的方法来编写更易于阅读和维护的异步代码,由于await会阻塞其后的代码必须仔细测试您的代码,并在性能开始受损时牢记这一点。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享