异步函数可能会一直存在,但有些人认为async/await可能会被抛弃。

为什么?

一个常见的误解是async/await和promise是完全不同的东西。

但其实async/await是基于promise的。

不要因为你使用了promise就被promise链给野蛮绑架了。

在本文中,我们将了解async/await如何让开发人员的生活变得更轻松,以及为什么要停止使用promise链。

让我们来看看一个promise链的例子:

getIssue()  .then(issue =\u0026gt; getOwner(issue.ownerId))  .then(owner =\u0026gt; sendEmail(owner.email, 'Some text'))

现在让我们看看async/await的等效代码:

const issue = await getIssue()const owner = await getOwner(issue.ownerId)await sendEmail(owner.email, 'Some text')

它看起来就像简单的语法糖,对吗?

与大多数人一样,我发现自己的代码看起来很简单、干净、易于阅读。但是,在修改代码时,似乎比预期的困难一些。

但这一点也不奇怪,这正是promise链的问题所在。下面让我们看看这是为什么。

易于阅读,易于维护

假设我们需要对之前的代码做出一个很小的修改(例如,我们需要在电子邮件内容中提及问题编号,比如“Some text #issue-number”)。

我们该怎么做?对于async/await版本,改起来很简单:

const issue = await getIssue()const owner = await getOwner(issue.ownerId)await sendEmail(owner.email, `Some text #${issue.number}`) // tiny change here

前两行不受影响,第三行只需要稍微改动一点点。

那么promise链版本呢?

在.then()中,我们可以访问owner,但不能访问issue。看看,promise链从这里开始就变得有点混乱了。我们可以试着这样修改:

getIssue()  .then(issue =\u0026gt; {    return getOwner(issue.ownerId)      .then(owner =\u0026gt; sendEmail(owner.email, `Some text #${issue.number}`))  })

正如你所看到的,一个小的调整就需要修改好几行代码(如getOwner(issue.ownerId))。

代码在不断发生变化

在开发新功能时尤其如此。例如,如果我们需要将异步调用getSettings()返回的结果包含在电子邮件内容中,该怎么办?

它可能看起来像这样:

const settings = await getSettings() // we added thisconst issue = await getIssue()const owner = await getOwner(issue.ownerId)await sendEmail(owner.email,  `Some text #${issue.number}. ${settings.emailFooter}`) // minor change here

如果使用promise链该怎样实现?可能是这样:

Promise.all([getIssue(), getSettings()])  .then(([issue, settings]) =\u0026gt; {    return getOwner(issue.ownerId)      .then(owner =\u0026gt; sendEmail(owner.email,        `Some text #${issue.number}. ${settings.emailFooter}`))  })

但是,对我来说,这些代码显得有点乱。每当我们需要做出修改时,都需要修改很多代码,这实在太恶心了!

因为我不想再嵌套then()调用,我可以并行地调用getIssue()和getSettings(),所以我使用了Promise.all(),然后进行一些解构。确实,这个版本与await版本相比更好,因为它可以并行运行 ,但它仍然难以阅读。

我们是否可以优化await版本,让它可以并行运行而不需要牺牲代码的可读性?让我们来看看:

const settings = getSettings() // we don't await hereconst issue = await getIssue()const owner = await getOwner(issue.ownerId)await sendEmail(owner.email,  `Some text #${issue.number}. ${(await settings).emailFooter}`) // we do it here

我删除了settings右侧的await,并在sendEmail()前面加上了await。我创建了一个promise,但在需要用到这个值之前不需要等待。与此同时,其他代码可以并行运行。就这么简单!

你不需要Promise.all()

我已经演示了如何在不使用Promise.all()的情况下轻松有效地并行运行promise。这意味着你不再需要Promise.all()了,对吧。

有些人可能会争辩说,还有一个情况,也就是当你有一个值数组时,你需要将它映射到一个promise数组。例如,你有一个要读取的文件名的数组,或者你需要下载的URL的数组,等等。

我认为他们错了。我的建议是使用外部库来处理并发。例如,我会使用bluebird中的Promise.map(),因为它支持设置并发限制。如果我要下载N个文件,可以指定同时下载的文件个数不超过M个。

你可以在任何地方使用await

async/await可以帮你简化你要做的事情。想象一下,如果使用promise链,下面这些表达式有多复杂。但是如果使用async/await,它们就会简单得多。

const value = await foo() || await bar()const value = calculateSomething(await foo(), await bar())

还说服不了你?

假设你对代码可阅读性和易维护性不感兴趣,相反,你更喜欢复杂性,那么好吧。

在代码中使用promise链时,开发者每次在调用then()时都会创建新函数。这会占用更多内存,而且这些函数总是处在另一个上下文中。因此,这些函数变成了闭包,这使垃圾回收变得更加困难。此外,这些匿名函数通常会污染堆栈跟踪。

现在,我们讨论的是堆栈跟踪:现在有一个提议用于为异步函数实现更好的堆栈跟踪。

只要开发人员坚持只使用异步函数和异步生成器,并且不会手动编写promise代码,因为如果使用了promise链,就无法实现更好的堆栈跟踪。

这也是总是使用async/await的另一个原因!

如何迁移

首先:开始使用异步函数并停止使用promise链。

其次,你可能已经发现Visual Studio Code可以非常方便地帮你实现迁移。

视频地址:https://twitter.com/umaar/status/1045655069478334464

结论

  • async/await已得到广泛支持,除非你需要支持IE。

  • async/await代码具有更好的可读性和可维护性。

  • 出于一些技术原因,最好是只使用async/await。

  • 借助Visual Studio Code或其他IDE,你可以轻松地迁移现有的promise链代码!

英文原文:https://blog.logrocket.com/promise-chaining-is-dead-long-live-async-await-445897870abc

有了async/await,你可以丢掉promise链了相关推荐

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

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

  2. angular2 学习笔记 ( Rxjs, Promise, Async/Await 的区别 )

    Promise 是 ES 6 Async/Await 是 ES 7 Rxjs 是一个 js 库 在使用 angular 时,你会经常看见这 3 个东西. 它们都和异步编程有关,有些情况下你会觉得用它们 ...

  3. js异步解决方案 --- 回调函数 vs promise vs generater/yield vs async/await

    javascript -- 深度解析异步解决方案 高级语言层出不穷, 然而唯 js 鹤立鸡群, 这要说道js的设计理念, js天生为异步而生, 正如布道者朴灵在 node深入浅出--(有兴趣的可以读一 ...

  4. promise用法_JavaScript中的async/await的用法和理解

    昨天更新的是"JavaScript中的Promise使用详解",其实也就是说了下基本用法和自己对Promise的理解,可能有错误之处,也欢迎指出.今天就说一说"JavaS ...

  5. async/await工作机制探究--NodeJS

    ES6中的async/await让Promise变得更加简便,通常await处理的链式Promise会包裹在函数中,返回结果仍然是一个Promise对象. 但是当await直接处理链式Promise时 ...

  6. async function_掌握 Async/Await

    摘要: 还不用Async/Await就OUT了.. 原文:掌握 Async/Await 作者:Jartto Fundebug经授权转载,版权归原作者所有. 前端工程师肯定都经历过 JS 回调链狱的痛苦 ...

  7. async/await面试题

    async await 什么是 async/await async/await特点 async/await优缺点 async/await对比Promise的优势 async/await 如何捕获异常 ...

  8. 微信小程序中使用async/await

    在之前写了微信小程序中如何使用promise,其实使用promise的最终目的是要能使用async/await. 同时要使用async/await也必须在promise的基础之上. 1.下载regen ...

  9. async await异步

    介绍Promise 既然有了promise 为什么还要有async await ? 因为promise 不是完美的异步解决方案,而 async await 的写法看起来更加简单且容易理解. Promi ...

最新文章

  1. PHP框架之间有什么区别,php框架和设计模式区别
  2. 多年iOS开发经验总结(一)
  3. unittest ResourceWarning: unclosed socket.socket fd=864, family=AddressFamily.AF_INET... 解决办法...
  4. 1.12 声明自定义异常
  5. Core Data(3)- 使用绑定
  6. C++利用SOCKET传送文件
  7. REVERSE-PRACTICE-BUUCTF-7
  8. sql2005 无法解决 equal to 操作Chinese_PRC_CI_AS 和 Chinese_PRC_CS_AS 之间的排序
  9. 2020中青杯B题股指与国家经济数学建模全过程文档及程序
  10. 《码农翻身》各章节阅读连接
  11. 我是这样对待曾经背叛我的女人的!
  12. 不吸电子烟也请别吸电子咖啡!我们向雪加电子咖啡发起了挑战
  13. kettle 9.x 版本连接资源库,资源库灰色
  14. Mysql 允许IP地址访问
  15. 神秘代码alpha191的终极打开方式
  16. 高校计算机教师年度考核,教师年度考核个人总结范文
  17. linux测试tcp长连接工具,Linux(服务器编程):44---TCP长连接、短连接(心跳检测)
  18. 在html中加入一个动态图片背景音乐,如何插入背景音乐和背景图片(附HTML语法教程地址)...
  19. 传音控股过会:核心技术说服力低 仍缺乏长期护城河
  20. iOS 开发中如何隐藏UINavigationBar

热门文章

  1. 提取数据_Origin如何提取图片数据
  2. 异常已存在具有相同键的条目。_灵敏度高,却已停产——山进PR-D3Plus DX收音机评测...
  3. python如何升级_python pip如何升级
  4. 黑马博客——详细步骤(八)项目功能的实现之另一种分页方式【mongoose-sex-page】
  5. mysql配置优化ya_mysql性能调优工具之mytop
  6. php 二进制 十六进制转换,php 实现进制转换(二进制、八进制、十六进制)互相转换实现代码...
  7. 计算机维修和维护实训报告,计算机维护与维修实训报告书.docx
  8. linux启动中继服务器失败,Tor中继服务器在Linux里安装配置的流程
  9. 做一个计算器_如何设计一个JavaScript插件系统,编程思维比死磕API更重要
  10. 数据库java_(六) Java数据库