10 分钟学会 JavaScript 的 Async/Await

摘要:在过去很长的一段时间里,JavaScript开发人员不得不依赖回调来处理异步代码。如果遇到赋值的逻辑,会发现,特别难处理维护,代码看起来也特别的糟糕。

前言

在之前很长的一段时间里,JavaScript开发人员不得不依赖回调来处理异步代码。如果遇到赋值的逻辑,会发现,特别难处理维护,代码看起来也特别的糟糕。

值得庆幸的是,后来出现了 Promises,它为回调提供了一种更有条理的替代方案。但是现在,由于 Async / Await 的出现, 编写 JavaScript 代码将变得更好!  

以前我们使用 callback。
后来我们使用 Promise。
现在我们使用 Async/Await。


什么是 Async/Await?

Async / Await是一个备受期待的JavaScript功能,它使异步函数的使用更加愉快和易于理解。它构建在Promises之上,并与所有现有的基于Promise的API兼容。

Async - 定义异步函数(async function someName(){...})

  • 自动把函数转换为 Promise
  • 当调用异步函数时,函数返回值会被 resolve 处理
  • 异步函数内部可以使用 await

Await - 暂停异步函数的执行 (var result = await someAsyncCall();)

  • 当使用在 Promise 前面时,await 等待 Promise 完成,并返回 Promise 的结果
  • await 只能和 Promise 一起使用,不能和 callback 一起使用
  • await 只能用在 async 函数中

下面是一个简单的例子:

假设我们想从服务器上获取一些JSON文件。我们将编写一个使用AXIOS库的函数,并将HTTP GET请求发送到 xxx.json。 我们必须等待服务器响应,所以这个HTTP请求自然是异步的。

下面我们可以看到相同的函数实现了两次。首先是Promise,然后是第二次使用异步/等待。

// Promise
function getJSON(){
    // 为了使函数阻塞,我们手动创建一个Promise。
    return new Promise( function(resolve) {
        axios.get('https://www.javanx.cn/example.json')
            .then( function(json) {
                // 我们使用resolve返回结果
                resolve(json);
            });
    });

}

// Async/Await
// async关键字将自动创建一个新的Promise并返回它
async function getJSONAsync(){

    // wait关键字使我们不必编写.then()块
    let json = await axios.get('https://tutorialzine.com/misc/files/example.json');

    // GET请求的结果在JSON变量中可用
    // 我们返回它,就像正常同步函数一样
    return json;
}

很明显,代码的Async / Await版本更短,更容易阅读。除了使用的语法之外,两个函数完全相同 - 它们都返回Promises并使用axios的JSON响应来解析。我们可以这样调用我们的异步函数:

getJSONAsync().then( function(result) {
    // Do something with result.
});

那么,Async / Await 会比 Promise更好嘛?

一点都不。使用Async / Await时,我们仍在使用Promise。从长远来看,对Promise的良好理解实际上对您有很大的好处。

甚至有一些用例Async / Await并不能解决问题,我们不得不回到Promise上,需求答案。

一个这样的场景,当我们需要进行多个独立的异步调用并等待所有这些调用完成时。

如果我们尝试使用async和await执行此操作,将发生以下情况:

async function getABC() {
  let A = await getValueA(); // 2 second to finish
  let B = await getValueB(); // 4 second to finish
  let C = await getValueC(); // 3 second to finish

  return A*B*C;
}

每个调用将等待前一个返回结果。由于我们一次只进行一次调用,整个功能从开始到结束需要9秒(2 + 4 + 3)。

这不是最佳解决方案,因为三个变量A,B和C不相互依赖。换句话说,在我们得到B之前,我们不需要知道A的值。我们可以同时得到它们并且等待几秒钟。

要同时发送所有请求,需要Promise.all()。这将确保执行后面函数之前我们仍然拥有所有结果,但异步调用将并行触发,而不是一个接一个地触发。

async function getABC() {
  // Promise.all()允许我们同时发送所有请求。
  let results = await Promise.all([ getValueA, getValueB, getValueC ]); 
  return results.reduce((total,value) => total * value);
}

这样,该功能将花费更少的时间。 getValueB和getValueC调用将在getValueB结束时完成。我们将有效地将执行时间减少到最慢请求的时间(getValueB - 4秒),而不是时间的总和。


处理Async / Await中的错误

在 Async/Await 语法中,我们可以使用 try/catch 进行错误处理。在 Promise 中的 .catch() 分支会进入 catch 语句。我们只需要像这样包装我们的Await:

async function doSomethingAsync(){
    try {
        // 此异步调用可能会失败.
        let result = await someAsyncCall();
    }
    catch(error) {
        // 我们将在这里发现错误
    }
}

catch子句将处理等待的异步调用,或我们在try块中编写的任何其他失败代码所引发的错误。

如果情况需要,我们还可以在执行异步函数时捕获错误。因为所有异步函数都返回Promise,所以在调用它们时我们可以简单地包含一个.catch()事件处理程序。

// 没有try / catch块的异步函数。
async function doSomethingAsync(){
    // This async call may fail.
    let result = await someAsyncCall();
    return result;  
}

// 我们在调用函数时捕获错误
doSomethingAsync().
    .then(successHandler)
    .catch(errorHandler);

根据自己的喜好,选择之中即可。同时使用try/catch和.catch()很可能会导致问题。


浏览器支持


Async / Await已在大多数主流浏览器中提供。排除IE11- 所有其他供应商将识别async/await代码,而无需外部库。


结语

通过添加Async / Await,JavaScript语言在代码可读性和易用性方面取得了巨大的飞跃。编写类似于常规同步函数的异步代码的能力将受到初学者和经验丰富的编码人员的青睐。


本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://shenqiku.cn/article/FLY_11120