发布于 4年前

JavaScript ES 2017: 通过示例学习Async/Await

预备知识

ES 2017新增了Asynchronous函数。 在JavaScript中,Async函数本质上是一种处理异步代码的比较简洁的方法。 为了理解这些是什么,以及它们是如何工作的,我们首先需要了解Promise。

如果你不知道Promise是什么,那么你应该先阅读我发表的关于Promise的这篇文章。 在理解Promise之前,你是不会理解JavaScript中的Async/Await。

Async/Await是什么?

  • JavaScript编写异步代码的最新方法
  • 它是非阻塞的(就像Promise和回调)。
  • Async/Await是为了简化使用和编写链接promise的过程。
  • Async/Await返回一个Promise。 如果函数抛出错误,Promise将被拒绝。 如果函数返回值,Promise将被解析。

语法

编写异步函数非常简单。 你只需要在function之前添加async关键字:

// 普通函数
function add(x,y){
  return x + y;
}
// 异步函数
async function add(x,y){
  return x + y;
}

Await

异步函数可以使用await表达式。 这将暂停async函数,并等待Promise解决之后再继续。

示例时间

说够了。 要了解这一切意味着什么,让我们看一个例子! 首先,我们将使用promise来创建一些代码。 一旦我们有了一些工作,我们将使用async/await重写我们的函数,这样你就可以看到它是多么的简单!

如果你使用Google Chrome,请在开发者控制台中输入代码。 您可以按Ctrl + Shift + J(Windows / Linux)或Cmd + Opt + J(Mac)打开控制台。

想想下面的代码:

function doubleAfter2Seconds(x) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(x * 2);
    }, 2000);
  });
}

在这段代码中,我们有一个叫做doubleAfter2Seconds的函数。 这个函数会以一个数字作为输入,并且在两秒钟后处理,数字加倍。

我们可以调用我们的函数,并传进10来试下。 为了做到这一点,我们将在传入10时调用函数。然后,在promise处理后,我们获取返回值并输出到控制台。 这是这样的:

doubleAfter2Seconds(10).then((r) => {
  console.log(r);
});

真棒!

但是如果我们想通过函数执行不同的值并累加结果? 不幸的是,我们不能将我们的调用加在一起并记录下来:

let sum =   doubleAfter2Seconds(10)
          + doubleAfter2Seconds(20)
          + doubleAfter2Seconds(30);
console.log(sum);
// undefined

上面的代码的问题是它实际上没有等待我们的promise处理就输出到控制台了。

一个可能的解决方案是建立一个promise链。 为此,我们创建一个名为addPromise的新函数。 我们的函数获得输入值,并将返回一个Promise。 以下是示例代码的样子:

function addPromise(x){
  return new Promise(resolve => {
    // 此处为代码   
    // resolve()
  });
}

真棒。 现在我们可以添加我们调用的doubleAfter2Seconds函数。 一旦我们完成了,我们可以用我们新的累加方法来处理了。 在这个例子中,我们应该返回x + 2 * a + 2 * b + 2 * c。 代码如下:

function addPromise(x){
  return new Promise(resolve => {
    doubleAfter2Seconds(10).then((a) => {
      doubleAfter2Seconds(20).then((b) => {
        doubleAfter2Seconds(30).then((c) => {
          resolve(x + a + b + c);
        })
      })
    })
  });
}

让我们再一次一行一行地看下代码。

  • 首先,我们创建了函数addPromise。 这个函数接受一个参数。

  • 接着,我们创建将要返回的新Promise。 请注意,为了简单起见,我们不处理拒绝/错误。

  • 接着,我们首次调用doubleAfter2Seconds,传递值10。两秒钟后,返回20给一个变量。

  • 我们再次调用doubleAfter2Seconds,这次传递的值为20.两秒钟后,返回40给变量b。

  • 我们最后一次调用doubleAfter2Seconds,这次传递的值是30.两秒钟后,返回60给变量c。

  • 最后,我们以10 + 20 + 40 + 60或130的值来处理Promise。

当我们把所有的代码放在一起时,看起来像这样:

function doubleAfter2Seconds(x) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(x * 2);
    }, 2000);
  });
}

function addPromise(x){
  return new Promise(resolve => {
    doubleAfter2Seconds(10).then((a) => {
      doubleAfter2Seconds(20).then((b) => {
        doubleAfter2Seconds(30).then((c) => {
          resolve(x + a + b + c);
        })
      })
    })
  });
}

addPromise(10).then((sum) => {
  console.log(sum);
});

从Promise切换到Async/Await

真棒! 现在让我们看看使用Async/Await编写上面的代码将更容易!

删除addPromise函数,并创建一个名为addAsync的新函数。 这个函数与我们的addPromise具有完全相同的用途。 在创建addPromise函数时,使用async关键字。 如下所示:

async function addAsync(x) {
  // code here...
}

现在你已经创建了一个异步函数,我们可以使用await关键字来暂停我们的代码,直到Promise解决。 这是多么容易:

async function addAsync(x) {
  const a = await doubleAfter2Seconds(10);
  const b = await doubleAfter2Seconds(20);
  const c = await doubleAfter2Seconds(30);
  return x + a + b + c;
}

这里是完整的代码:

function doubleAfter2Seconds(x) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(x * 2);
    }, 2000);
  });
}

async function addAsync(x) {
  const a = await doubleAfter2Seconds(10);
  const b = await doubleAfter2Seconds(20);
  const c = await doubleAfter2Seconds(30);
  return x + a + b + c;
}

addAsync(10).then((sum) => {
  console.log(sum);
});

正如你所看到的,我们仍然使用doubleAfter2Seconds函数。 同样,我们调用addAsync()函数并传入值10。完成后记录结果值。 让我们一步步地过:

  • 首先我们调用addAsync(10)传入10。

  • 接着,我们在第10行获取a的值。由于使用了关键字await,函数暂停了两秒钟,等待Promise处理。 一旦Promise处理了,得到a = 20。

const a = await doubleAfter2Seconds(10);
  • 接着,我们在第11行获取b的值。由于使用了关键字await,函数在等待Promise处理的时候暂停了两秒钟。 一旦Promise处理了,得到b = 40。
const b = await doubleAfter2Seconds(20);
  • 接着,我们在第12行获取c的值。由于使用了关键字await,函数在等待Promise处理的时候暂停了两秒钟。 一旦Promise处理了,得到c = 60。
const c = await doubleAfter2Seconds(30);
  • 最后,我们可以返回x + a + b + c的值。 因为以10作为参数,所以返回10 + 20 + 40 + 60的值。

  • 六秒钟后,console.log(sum)终于运行了。 传入10 + 20 + 40 + 60的值,并将130输出到控制台。

就是这样! 你刚刚用JavaScript中创建了一个异步函数!

正如你所看到的,由于异步函数返回一个Promise,所以它们可以很容易地与Promises交替使用。 当我们使用Async/Await而不是长的Promise链时,我们的代码也更清晰易读。

©2020 edoou.com   京ICP备16001874号-3