-
Notifications
You must be signed in to change notification settings - Fork 442
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to escape async/await hell #65
Comments
原来并行的异步操作,写成串行的,好傻啊。:-) 这文章标题党啊 |
@njleonzhang 你看了英文原文吗? |
@dwqs 本来没看,你一说我去看了一下,和你这篇文章基本一个意思。 最后感谢您的高产博客文章,很多让我受益匪浅。偶有吐槽,也不针对您,请不要介意。 |
@njleonzhang 我不是说你怼我 文章中列出的这种现象是客观存在的 19k+ 的赞同表明很多人都认可原作者的观点 并且可能很多人之前就是把「原来并行的异步操作,写成串行的」 我相信这种现象在国内也存在不少 标题党的原因可能是我的问题 标题我是直译过来的 |
@dwqs 这个应该不是你的锅,这个作者应该就是这个意思。也许这个很多人并不知道(没注意) 随便google下: |
赞同 @njleonzhang 的观点。。这本质上并不是async、await的锅。。另外,forEach也可以解决文中的问题。 |
熟悉js异步编程思维的开发者不会这么干,async、await 用的多的都是从其他语言转过来的服务端开发者,因为习惯同步执行的代码编写风格,按着这个思路事事滥用 async、await,才有了这篇文章 |
@php-cpm 现在都流行这么写了啊。async、await 的代码看着还是挺舒服的。 |
async/await 是 ES7 的新语法。在 async/await 标准出来之前,JavaScript 的异步编程经历了 callback --> promise --> generator 的演变过程。在 callback 的时代,最让人头疼的问题就是回调地狱(callback hell)。所以,在 async/await 一经推出,社区就有人认为「这是 JavaScript 异步编程的终极解决方案」。
但 async/await 也可能带来新的问题。
最近阅读了 Aditya Agarwal 的一篇文章:How to escape async/await hell。这篇文章主要讨论了过度使用 async/await 导致的新的「地狱」问题,其已经在 Medium 上获得了 19k+ 的 Applause。
何为 async/await 地狱
在编写异步代码时,人们总是喜欢一次写多个语句,并且在一个函数调用之前使用
await
关键字。这可能会导致性能问题,因为很多时候一个语句并不依赖于前一个语句——但使用await
关键字后,你就需要等待前一个语句完成。示例
假设你要写一个订购 pizza 和 drink 的脚本,代码可能是如下这样的:
这段代码开起来没什么问题,也能正常的运行。但是,这并不是一个好的实现,因为这把本身可以并行执行的任务变成了串行执行。
选择一个 drink 添加到购物车和选择一个 pizza 添加到购物车可以看作是两个任务,而这两个任务之间并没有相互依赖的关系,也没有特定的顺序执行关系。所以这两个任务是可以并行执行的,这样能提高性能。而上述代码将二者变成了串行执行,显然是降低了程序性能的。
更糟糕的例子
假设要写一个程序,根据 followers 数用来显示 Github 中国区用户的排名情况。
如果只是获取排名,我们可以调用 Github 官方的 Search users 接口,伪代码如下:
调用
getUserRank
函数就能获取到想要的结果。但是,你可能还要想要获取每个用户的 follower 数、email、地区和仓库等数据,而 Search users 接口并没有返回这些数据,你可能需要再去调用 Single user 接口。然后上述代码可能被改写为:
运行查看结果,自己想要的数据都拿到了。但是,你发现一个问题,程序运行时间有点长,该怎么优化下呢?
其实,铺垫了这么长,就是想说明一个问题:你陷入了 async/await 的地狱。
上述代码的问题在于,获取每个用户资料的请求并不存在依赖性,就类似上文中的选择 pizza 和 drink 一样,这是可以并行执行的请求。而根据上述代码,请求都变成了串行执行,这当然会损耗程序的性能。
按照上述代码,可以看一下其异步请求的动态图:
可以看到,获取用户资料的每个请求都需要等到上一个请求完成之后才能执行,Waterfall 处于一个串行的状态。那要怎么改进这个问题呢?
既然获取每个用户资料的请求并不存在依赖性,那么我们可以先触发异步请求,然后延迟处理异步请求的结果,而不是一直等该请求完成。根据这个思路,那可能改进的代码如下:
可以看一下异步请求的动态图:
可以看到,获取用户资料的异步请求处理不再是串行执行,而是并行执行了,这将大大提高程序的运行效率和性能。
总结
Aditya Agarwal 在其文章中也给出了怎么避免陷入 async/await 地狱的建议:
参考
The text was updated successfully, but these errors were encountered: