[译]JavaScript async / await:好处、坑和正确用法

栏目: JavaScript · 发布时间: 7年前

内容简介:原文地址:ES7通过介绍

原文地址: JavaScript async/await: The Good Part, Pitfalls and How to Use

ES7通过介绍 async/await 使得JavaScript的异步编程实现了重大改进。它提供了一种使用同步代码样式异步访问 resoruces 的方式,而且不会阻塞主线程。然而,使用它有点棘手。在本文中,我们将从不同的角度探讨 async/await ,并将展示如何正确有效地使用它们。

async/await的好处

async/await 给我们带来的最重要的好处是同步编程风格。我们来看一个例子吧。

[译]JavaScript async / await:好处、坑和正确用法
很明显, async/await 版本比 promise 版本更容易理解。如果忽略 await

关键字,代码看起来就像任何其他同步语言,如Python。

好的一面不仅是可读性, async/await 有本地浏览器支持。截至今天,所有主流浏览器查看都完全支持异步功能。

[译]JavaScript async / await:好处、坑和正确用法

本机支持意味着您不必转换代码。更重要的是,它有助于调试。当您在函数入口设置断点并跳过 await 行时,您将看到调试器在 bookModel.fetchAll() 执行期间暂停一段时间,然后移动到下一 行 .filter !这比 promise 情况要容易得多,在 promise 情况下你必须在 .filter 行设置另一个断点 。

[译]JavaScript async / await:好处、坑和正确用法
另一个不太明显的好处是 async 关键字。它声明 getBooksByAuthorWithAwait() 函数返回值确保是一个 promise ,以便调用者可以安全调用 getBooksByAuthorWithAwait().then(...)await getBooksByAuthorWithAwait()

。看看下面的代码(不好的做法!):

[译]JavaScript async / await:好处、坑和正确用法
在上面的代码中, getBooksByAuthorWithPromise 可以返回一个 promise (正常情况)或一个 null 值(例外情况),在这种情况下,调用者不能安全地调用 .then() 。通过 async 声明,这种返回 null

的情况将不可能出现。

Async/await可能会产生误导

有些文章将 async/awaitPromise 进行比较,并声称它是JavaScript异步编程演变的下一代,我表示不同意。 Async/await 是一种改进,但它只不过是一种语法糖,它不会完全改变我们的编程风格。

从本质上讲, await 函数仍然是 promise 。在正确使用 await 函数之前,您必须了解 promises ,还有就是,大多数情况下您需要同时使用 promises 和异步函数。

考虑上面示例中的 getBooksByAuthorWithAwait()getBooksByAuthorWithPromises() 函数。请注意,它们不仅在功能上相同,而且具有完全相同的接口。

如果直接调用 getBooksByAuthorWithAwait() ,这意味着将返回一个 promise

嗯,这并不是坏事。只是 await 这个名称让人感觉“哦,这可以将异步函数转换为同步函数”,这实际上是错误的。

Async/await的坑

那么使用 async/await 时会出现什么错误?以下一些常见的情况。

太顺序了

虽然 await 可以使您的代码看起来像同步,但请记住它们仍然是异步的,必须注意避免过于顺序。

[译]JavaScript async / await:好处、坑和正确用法

此代码看起来逻辑正确。但这是错误的。

  1. await bookModel.fetchAll() 将等到 fetchAll() 返回。
  2. 然后 await authorModel.fetch(authorId) 将被调用。 请注意authorModel.fetch(authorId) 它不依赖于 bookModel.fetchAll() 的结果,实际上它们可以并行调用!但是,通过 await 在这里使用,这两个调用变为顺序,并且总执行时间将比并行版本长得多。

这是正确的方法:

[译]JavaScript async / await:好处、坑和正确用法
或者更糟糕的是,如果你想逐个获取一个列表的项,必须依赖 promise

[译]JavaScript async / await:好处、坑和正确用法
简单地说,您仍然需要异步考虑工作流,然后尝试同步编写代码 await 。在复杂的工作流程中,直接使用 promises

可能更容易。

错误处理

使用 promises ,异步函数有两个可能的返回值:已解析的值和被拒绝的值。我们可以 .then() 用于正常情况, .catch() 用于特殊情况。但是, async/await 错误处理可能会很棘手。

try…catch

最标准的(我推荐的)方法是使用 try...catch 语句。当一个 await 调用时,任何被拒绝的值都将作为异常抛出。这是一个例子:

[译]JavaScript async / await:好处、坑和正确用法
catch

的错误正是被拒绝的值。在我们发现异常后,有几种方法来处理它:

  1. 处理异常,并返回正常值。(不在 catch 块中使用任何 return 语句,这等同于使用 return undefined ,也是正常值。)
  2. 抛出它,如果你想让调用者处理它。可以直接抛出普通的错误对象 throw error ,这在 promise 链中允许使用 async getBooksByAuthorWithAwait() 函数(即仍然可以像这样调用它 getBooksByAuthorWithAwait().then(...).catch(error => ...) ); 或者可以使用 Error 对象包装错误,例如 throw new Error(error) ,当控制台中显示此错误时,将提供完整的堆栈跟踪。
  3. 拒绝它,就像 return Promise.reject(error) 。这相当于 throw error 不推荐。

使用try...catch的好处是:

  • 简单,传统。只要您有 Java 或C++等其他语言的经验,就不会有任何困难。
  • 如果不需要每步执行错误处理,仍然可以在一个 try...catch 块中包装多个 await 调用在一个位置处理错误。

这种方法也存在一个缺陷。由于 try...catch 将捕获块中的每个异常,因此将会捕获一些通常不会被 promises 捕获的异常。想想这个例子:

[译]JavaScript async / await:好处、坑和正确用法
运行此代码,您将在控制台中收到 ReferenceError: cb is not defined 错误。错误是由 console.log() 输出而不是JavaScript本身。有时这可能是致命的。如果 BookModel

被深深地包含在一系列函数调用中,并且其中一个调用吞噬了错误,那么找到这样的未定义错误将非常困难。

使函数返回两个值

另一种错误处理方式受 Go 语言的启发。它允许异步函数返回错误和结果。有关详细信息,请参阅此博客文章: How to write async await without try-catch blocks in Javascript

简言之,您可以使用这样的 await 函数:

[译]JavaScript async / await:好处、坑和正确用法

我个人不喜欢这种方法,因为它将Go风格带入JavaScript,感觉不自然,但在某些情况下,这可能非常有用。

使用.catch

我们将在这里介绍的最后一种方法是继续使用 .catch()

回想一下 await 的功能:它将等待 promise 完成其工作。再回想一下, promise.catch() 也将是一个 promise ,所以我们可以像这样编写错误处理:

[译]JavaScript async / await:好处、坑和正确用法

这种方法有两个小问题:

  1. 它是 promisesawait 函数的混合体。您仍然需要了解 promises 的工作原理。
  2. 错误处理在正常路径之前进行,这样不直观。

结论

ES7引入的关键字 async/await 肯定是对JavaScript异步编程的改进。它可以使代码更容易阅读和调试。然而,为了正确使用它们,必须完全理解 promise ,因为它们只不过是语法糖,而潜在的技术仍然是 promise


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Java程序员修炼之道

Java程序员修炼之道

[英] Benjamin J. Evans、[荷兰] Martijn Verburg / 吴海星 / 人民邮电出版社 / 2013-7 / 89.00元

本书分为四部分,第一部分全面介绍Java 7 的新特性,第二部分探讨Java 关键编程知识和技术,第三部分讨论JVM 上的新语言和多语言编程,第四部分将平台和多语言编程知识付诸实践。从介绍Java 7 的新特性入手,本书涵盖了Java 开发中最重要的技术,比如依赖注入、测试驱动的开发和持续集成,探索了JVM 上的非Java 语言,并详细讲解了多语言项目, 特别是涉及Groovy、Scala 和Cl......一起来看看 《Java程序员修炼之道》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具