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

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

async/await的好处

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

很明显,async/await版本比promise版本更容易理解。如果忽略await关键字,代码看起来就像任何其他同步语言,如Python。

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

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

另一个不太明显的好处是async关键字。它声明getBooksByAuthorWithAwait()函数返回值确保是一个promise,以便调用者可以安全调用getBooksByAuthorWithAwait().then(...)await getBooksByAuthorWithAwait()。看看下面的代码(不好的做法!):在上面的代码中,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可以使您的代码看起来像同步,但请记住它们仍然是异步的,必须注意避免过于顺序。

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

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

这是正确的方法:

或者更糟糕的是,如果你想逐个获取一个列表的项,必须依赖promise: 简单地说,您仍然需要异步考虑工作流,然后尝试同步编写代码await。在复杂的工作流程中,直接使用promises可能更容易。

错误处理

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

try…catch

最标准的(我推荐的)方法是使用try...catch语句。当一个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捕获的异常。想想这个例子:

运行此代码,您将在控制台中收到ReferenceError: cb is not defined错误。错误是由console.log()输出而不是JavaScript本身。有时这可能是致命的。如果BookModel被深深地包含在一系列函数调用中,并且其中一个调用吞噬了错误,那么找到这样的未定义错误将非常困难。

使函数返回两个值

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

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

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

使用.catch

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

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

这种方法有两个小问题:

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

结论

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

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

  1. javascript async await

    参考: https://segmentfault.com/a/1190000007535316 https://zhuanlan.zhihu.com/p/74637286

  2. Java什么时候提高境界支持async/await写法啊?

    2019独角兽企业重金招聘Python工程师标准>>> 异步编程的最高境界,就是根本不用关心它是不是异步 .NET的async/await方式最先达到了这个境界. 和async/aw ...

  3. 在.NET中执行Async/Await的两种错误方法

    微信公众号:架构师高级俱乐部 关注可了解更多的编程,架构知识.问题或建议,请公众号留言; 如果你觉得此文对你有帮助,欢迎转发 在.NET中执行异步/等待的两种错误方法 在应用开发中,我们为了提高应用程 ...

  4. kotlin协程async await的异常踩坑以及异常处理的正确姿势

    使用Kotlin来做一些异步操作相信大家都非常熟悉了,特别是结合Jetpack的一些组件,使得我们在Android开发中写异步任务非常的方便. 但是,关于在使用协程的时候,个人觉得异常处理这一块是相对 ...

  5. [译] JavaScript 如何工作的: 事件循环和异步编程的崛起 + 5 个关于如何使用 async/await 编写更好的技巧...

    原文地址:How JavaScript works: Event loop and the rise of Async programming + 5 ways to better coding wi ...

  6. JavaScript是如何工作的:事件循环和异步编程的崛起+ 5种使用 async/await 更好地编码方式!...

    此篇是 JavaScript是如何工作的第四篇,其它三篇可以看这里: JavaScript是如何工作的:引擎,运行时和调用堆栈的概述! JavaScript是如何工作的:深入V8引擎&编写优化 ...

  7. 【转】2.2[译]async/await中阻塞死锁

    这篇博文主要是讲解在async/await中使用阻塞式代码导致死锁的问题,以及如何避免出现这种死锁.内容主要是从作者Stephen Cleary的两篇博文中翻译过来. 原文1:Don'tBlock o ...

  8. 理解 JavaScript 的 async/await

    随着 Node 7 的发布,越来越多的人开始研究据说是异步编程终级解决方案的 async/await.我第一次看到这组关键字并不是在 JavaScript 语言里,而是在 c# 5.0 的语法中.C# ...

  9. JavaScript 的 async/await 理解(4)

    随着 Node 7 的发布,越来越多的人开始研究据说是异步编程终级解决方案的 async/await.我第一次看到这组关键字并不是在 JavaScript 语言里,而是在 c# 5.0 的语法中.C# ...

最新文章

  1. 专家也要小心,HTTPS网址的网站就一定安全吗?
  2. 历史性难题——如何为Kafka挑选合适的分区数?
  3. mysql的tmp_table_size和max_heap_table_size
  4. USACO1.5 Number Triangles(numtri)
  5. 音视频技术开发周刊 | 203
  6. 监听输入 vue_深度对比vue与react创建APP的差别,值得收藏
  7. 微服务跨数据库联合查询_MySQL数据库联合查询
  8. 4013-基于深度优先搜索的两顶点路径存在与否的判断(C++,附详细思路)
  9. 查看gradle dependencies
  10. 未找到适用于完成此操作的图像处理组件_一张图片竟带来如此风险?苹果操作系统多媒体处理组件暗含严重隐患...
  11. C++之左值引用与右值引用
  12. 与MyBatis的第一次见面课
  13. 3S基础知识:VB中利用MapX创建用户定制工具
  14. python读取pdf翻译生成word
  15. 【JavaScript】支持js代码的博客有…
  16. GitBash和GitGui右键失效解决方法
  17. 【Python】py3.6请求网站时报错:http.client.RemoteDisconnected: Remote end closed connection without response
  18. 阿里云dataV大屏可视化的使用攻略——vue项目
  19. BDH,CDH,DDH,DLP是什么?
  20. dubbo之SPI Wrapper分析

热门文章

  1. Elasticsearch(一) ES之简介、倒排索引介绍以及 elasticsearch、kibana安装
  2. Redis面试常问-- Redis常用数据类型
  3. vuex:弄懂mapState、mapGetters、mapMutations、mapActions
  4. kafka专题:kafka的总控制器Controller、消费者重分配策略等核心设计原理详解
  5. spring框架的深入理解
  6. 电脑突然卡主动不了了_必看!电脑运行卡或软件卡死无响应,怎么办?
  7. linux下C语言简单实现线程池
  8. kibana-7.3.0安装配置
  9. 实战:轻量级分布式文件系统FastDFS(GraphicsMagick图片压缩)
  10. java使用nio读写文件