boost log 能不能循环覆盖_如何在 JS 循环中正确使用 async 与 await
引言
async / await是ES7的重要特性之一,也是目前社区里公认的优秀异步解决方案。目前,async / await这个特性已经是stage 3的建议
然而,由于部分开发人员对该语法糖原理的认识不够清晰,泛滥而不加考虑地随意使用async/await ,可能会我们陷入了新的麻烦之中。
概述
下面是随处可见的现代化前端代码:
(async () => {
const pizzaData = await getPizzaData(); // async call
const drinkData = await getDrinkData(); // async call
const chosenPizza = choosePizza(); // sync call
const chosenDrink = chooseDrink(); // sync call
await addPizzaToCart(chosenPizza); // async call
await addDrinkToCart(chosenDrink); // async call
orderItems(); // async call
})();
await 语法本身没有问题,有时候可能是使用者用错了。当 pizzaData 与 drinkData 之间没有依赖时,顺序的 await 会最多让执行时间增加一倍的 getPizzaData 函数时间,因为 getPizzaData 与 getDrinkData应该并行执行。
回到我们吐槽的回调地狱,虽然代码比较丑,带起码两行回调代码并不会带来阻塞。
看来语法的简化,带来了性能问题,而且直接影响到用户体验,是不是值得我们反思一下?
正确的做法应该是先同时执行函数,再 await 返回值,这样可以并行执行异步函数:
(async () => {
const pizzaPromise = selectPizza();
const drinkPromise = selectDrink();
await pizzaPromise;
await drinkPromise;
orderItems(); // async call
})();
或者使用 Promise.all
可以让代码更可读:
(async () => {
Promise.all([selectPizza(), selectDrink()]).then(orderItems); // async call
})();
看来不要随意的 await,它很可能让你代码性能降低。
精读
仔细思考为什么 async/await 会被滥用,笔者认为是它的功能比较反直觉导致的。
首先 async/await 真的是语法糖,功能也仅是让代码写的舒服一些。先不看它的语法或者特性,仅从语法糖三个字,就能看出它一定是局限了某些能力。
举个例子,我们利用 html 标签封装了一个组件,带来了便利性的同时,其功能一定是 html 的子集。又比如,某个轮子哥觉得某个组件 api 太复杂,于是基于它封装了一个语法糖,我们多半可以认为这个便捷性是牺牲了部分功能换来的。
功能完整度与使用便利度一直是相互博弈的,很多框架思想的不同开源版本,几乎都是把功能完整度与便利度按照不同比例混合的结果。
那么回到 async/await 它的解决的问题是回调地狱带来的灾难:
a(() => {
b(() => {
c();
});
});
为了减少嵌套结构太多对大脑造成的冲击,async/await 决定这么写:
await a();
await b();
await c();
虽然层级上一致了,但逻辑上还是嵌套关系,这不是另一个程度上增加了大脑负担吗?而且这个转换还是隐形的,所以许多时候,我们倾向于忽略它,所以造成了语法糖的滥用。
理解语法糖
虽然要正确理解 async/await 的真实效果比较反人类,但为了清爽的代码结构,以及防止写出低性能的代码,还是挺有必要认真理解 async/await 带来的改变。
首先 async/await 只能实现一部分回调支持的功能,也就是仅能方便应对层层嵌套的场景。其他场景,就要动一些脑子了。
比如两对回调:
a(() => {
b();
});
c(() => {
d();
});
如果写成下面的方式,虽然一定能保证功能一致,但变成了最低效的执行方式:
await a();
await b();
await c();
await d();
因为翻译成回调,就变成了:
a(() => {
b(() => {
c(() => {
d();
});
});
});
然而我们发现,原始代码中,函数 c
可以与 a
同时执行,但 async/await 语法会让我们倾向于在 b
执行完后,再执行 c
。
所以当我们意识到这一点,可以优化一下性能:
const resA = a();
const resC = c();
await resA;
b();
await resC;
d();
但其实这个逻辑也无法达到回调的效果,虽然 a
与 c
同时执行了,但 d
原本只要等待 c
执行完,现在如果 a
执行时间比 c
长,就变成了:
a(() => {
d();
});
看来只有完全隔离成两个函数:
(async () => {
await a();
b();
})();
(async () => {
await c();
d();
})();
或者利用 Promise.all
:
async function ab() {
await a();
b();
}
async function cd() {
await c();
d();
}
Promise.all([ab(), cd()]);
这就是我想表达的可怕之处。回调方式这么简单的过程式代码,换成 async/await 居然写完还要反思一下,再反推着去优化性能,这简直比回调地狱还要可怕。
而且大部分场景代码是非常复杂的,同步与 await 混杂在一起,想捋清楚其中的脉络,并正确优化性能往往是很困难的。但是我们为什么要自己挖坑再填坑呢?很多时候还会导致忘了填。
原文作者给出了 Promise.all
的方式简化逻辑,但笔者认为,不要一昧追求 async/await 语法,在必要情况下适当使用回调,是可以增加代码可读性的。
总结
async/await 回调地狱提醒着我们,不要过渡依赖新特性,否则可能带来的代码执行效率的下降,进而影响到用户体验。同时,笔者认为,也不要过渡利用新特性修复新特性带来的问题,这样反而导致代码可读性下降。
*声明:本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。
公众号ID:tzbc666扫码关注最新动态点个好看和转发也是一种支持哟!
boost log 能不能循环覆盖_如何在 JS 循环中正确使用 async 与 await相关推荐
- mysql 存储过程 条件_如何在MySQL存储过程中正确实现条件?
要在存储过程中设置条件,请使用以下语法-if yourCondition then yourStatement1; else yourStatement2'; end if ; end // 让我们实 ...
- ios 控件徽章_如何在iOS 8中正确设置应用程序徽章值?
KepPM.. 22 以前帖子的附加信息(完整版registerUserNotificationSettings): Apple为注册通知和使用徽章制作了新的API. 请参阅WWDC 2014会话视频 ...
- jsfor循环终止_详解如何在JS代码中消灭for循环
Edit: 在我入职第三家公司的第一天,看到代码库里面一堆的 for 循环,内心有些崩溃,于是做了一次技术分享,展示怎样在代码中避免 for 循环.这篇文章是那次分享的总结.本文并不完美,其中递归的部 ...
- java js跳出循环_[Java教程]js循环的总结
[Java教程]js循环的总结 0 2016-10-07 15:00:14 js原生的循环有两种,一般的for循环和for...in循环.还有一种常用jQuery.each()循环. 一. js原生循 ...
- 为什么双层循环 冒泡排序_冒泡排序的双重循环理解
主要说一下冒泡排序的一些关键地方的个人理解,比如算法思想,两个循环的作用意义,中间循环变量范围的确定等. 原理:比较两个相邻的元素,将值大的元素交换至右端. 思路:依次比较相邻的两个数,将小数放在前面 ...
- do while循环语句_流程控制之循环语句【while循环语句】
while循环语句 while语句也称条件判断语句,它的循环方式为利用一个条件来控制是否要继续反复执行这个语句. 语法如下: while(条件表达式){ 执行语句 } 条件表达式:这是用于控制循环的条 ...
- birt脚本for循环语句_如何使用 for 循环语句嵌套方法!
for循环语法: for( 表达式1:表达式2:表达式3) { 循环体 } 循环从表达式1开始 - 表达式2(判别表达式)- 真 - 执行循环体 - 表达式3 - 判断表达式2 真 : 继续 - 循环 ...
- pythonfor循环列表_如何在Python中通过for循环传递列表列表?
我有一份清单:sample = [['TTTT', 'CCCZ'], ['ATTA', 'CZZC']] count = [[4,3],[4,2]] correctionfactor = [[1.33 ...
- 如何在 JS 代码中消灭 for 循环
Edit: 在我入职上一家公司的第一天,看到代码库里面一堆的 for 循环,内心有些崩溃,于是做了一次技术分享,展示怎样在代码中避免 for 循环.这篇文章是那次分享的总结.至于为什么我提倡避免 fo ...
最新文章
- 拉普拉斯平滑处理 Laplace Smoothing
- ORACLE分区表删除分区数据
- MATLAB应用实战系列NSGA-II多目标优化算法原理及应用实例(附MATLAB代码)
- 高级会计师资格考试成绩合格证在全国范围内几年有效
- Gym - 101173H Hangar Hurdles(bfs+克鲁斯卡尔重构树)
- 19年8月 字母哥 第四章 常用web开发数据库框架 不要用公司网络加载不出来 用热点!!!
- stm32仿真不能设置断点_使用LiteOS Studio图形化查看LiteOS在STM32上运行的奥秘
- JWT(JSON Web Token)的基本原理
- 【学习笔记】尚硅谷大数据项目之Flink实时数仓---数据采集
- 小米pro15拆机_小米笔记本拆解
- 上海大华条码称代码_上海大华条码秤使用说明书样本
- 深度学习Hello World --- 手写体识别 实战
- Unity PC打包后日志查看
- Tektronix泰克MDO3054示波器
- 正态分布在数据分析中的应用
- [cesium] 卫星雷达传感器,雷达探测效果
- PLC通过智能网关实现HTTP-Server接口(带Postman测试截图)
- [管理]_[选择合适的项目-任务管理工具Jira Redmine Trac对比]
- 如何下载保定市卫星地图高清版大图
- HEIF图像解码器FPGA/ASIC IP