ES7 Async/Await 陷阱
什么是Async/Await
ES6新增了Promise函数用于简化项目代码流程。然而在使用promise时,我们仍然要使用callback,并且并不知道程序要干什么,例如:
function doSomething() {
let i = 0;
waitOneSecond() // 返回一个Promise对象
.then(() => console.log(i));
i = 5;
}
最终console.log(i) 的结果是5,并不是0
为此,ES7引入了async函数,前面的例子可以改写这样:
async function doSomething() {
let i = 0;
await waitOneSecond();// 等待1秒
console.log(i);
i = 5;
}
这段代码片段中console.log(i)的结果是0。其中关键字await停止当前函数的执行,直到waitOneSecond()返回的promise对象状态变更为fulfilled(完成),并产生其返回值。
当返回的promise对象的状态变更为rejected(失败),错误信息会被 try/catch 代码块所捕获。
常见陷阱
效率损失:
乱用async/await,可能导致低效的设计模式。例如,假设我们想从数据库中获得一些用户他们的年龄平均。我们会这样做的:
async function getUserAge(userId) {
await waitOneSecond();// 等待1秒
return 7;
}
async function getAverageAge(userIds) {
let sumOfAges = 0;
let numOfUsers = userIds.length;
for (let userId of userIds) {
sumOfAges += await getUserAge(userId);
}
return sumOfAges / numOfUsers;
}
显而易见,这是错误的,假设我们有5个用户,上面的代码片段会轮训所有的用户并且等待每一个单独调用数据库,所以最终整个函数的等待时间是5秒。
为了更好的性能,降低等待时间,修改如下:
async function getAverageAge(userIds) {
let sumOfAges = 0;
let numOfUsers = userIds.length;
let agesPromises = userIds.map(getUserAge);//将每个用户对应的promise对象封装到数组中
let ages = await Promise.all(agesPromises);//使用Promise.all调用
for (let age of ages) {
sumOfAges += age;
}
return sumOfAges / numOfUsers;
}
修改之后,代码变得复杂了一些,但是所有的数据库调用,都是同时进行的。无论你有多少用户,这个方法的等待时间只需要1秒。
在使用async/await函数时,当函数体内需要使用await多次调用外部函数并且函数返回值彼此无依赖关系时,使用Promise.all降低函数整体的等待时间。
变量污染:
当使用async函数时,会令代码更易阅读,但是他们并不是真正的将你的代码变为同步,只是promise的语法糖而已,看下面这个例子
let currentUserId = 0;
async function getInfoAboutUser() {
currentUserId++; // 令每个用户id均唯一
let data = await waitTenSeconds(); // 获取某些其他数据,等待时间10秒
return { id: currentUserId , data };
}
async function registerUser() {
let user = await getInfoAboutUser();
await storeUser(user);
}
现在假设,有2个不同的用户接连注册,getInfoAboutUser 函数将被接连执行,当10秒的等待时间结束后,2个用户的id都是相同的。
在这个例子中,我们可以很简单的避免这个问题:
async function getInfoAboutUser() {
let data = await waitTenSeconds(); // 获取某些其他数据,等待时间10秒
currentUserId++; //令每个用户id均唯一
return { id: currentUserId };
}
结语
async/await函数的出现,极大的提高了javascript代码的可读性,但是他们并不是魔法,依然有很多未知的问题等待我们去发现。
我希望你喜欢这篇文章,并认为它游泳。如果有其他的陷阱,或者有任何疑问,请在评论中让我知道
ES7 Async/Await 陷阱的更多相关文章
- javascript ES6 新特性之 Promise,ES7 async / await
es6 一经推出,Promise 就一直被大家所关注.那么,为什么 Promise 会被大家这样关注呢?答案很简单,Promise 优化了回调函数的用法,让原本需要纵向一层一层嵌套的回调函数实现了横向 ...
- 理解 es7 async/await
简介 JavaScript ES7 中的 async / await 让多个异步 promise 协同工作起来更容易.如果要按一定顺序从多个数据库或者 API 异步获取数据,你可能会以一堆乱七八糟的 ...
- es7 async/await使用
先创建一个promise对象,里面执行一个异步函数 function fetchUser() { return new Promise((resolve, reject) => { fetch( ...
- 【译】JavaScript async / await:好的部分,陷阱和如何使用
async/await提供了一种使用同步样式代码异步访问资源的选项,而不会阻塞主线程.然而,使用它有点棘手.在本文中,我们将从不同的角度探讨async / await,并将展示如何正确有效地使用它们. ...
- JavaScript async/await:优点、陷阱及如何使用
翻译练习 原博客地址:JavaScript async/await: The Good Part, Pitfalls and How to Use ES7中引进的async/await是对JavaSc ...
- JavaScript ES7 中使用 async/await 解决回调函数嵌套问题
原文链接:http://aisk.me/using-async-await-to-avoid-callback-hell/ JavaScript 中最蛋疼的事情莫过于回调函数嵌套问题.以往在浏览器中, ...
- ES7前端异步玩法:async/await理解
在最新的ES7(ES2017)中提出的前端异步特性:async.await. 什么是async.await? async顾名思义是"异步"的意思,async用于声明一个函数是异步的 ...
- 关于ES7中的async/await在客户端和服务端上的实践
一.前言 在项目中经常遇到处理异步请求的情况,面对层层的嵌套,回调显示那么苍白无力: async / await是ES7的重要特性之一,也是目前社区里公认的优秀异步解决方案,既然这样就用上吧. 二.配 ...
- 理解ES7中的async/await
理解ES7中的async/await 优势是:就是解决多层异步回调的嵌套 从字面上理解 async/await, async是 "异步"的含义,await可以认为是 async w ...
随机推荐
- Zookeeper管理多个HBase集群
zookeeper是hbase集群的"协调器".由于zookeeper的轻量级特性,因此我们可以将多个hbase集群共用一个zookeeper集群,以节约大量的服务器.多个hbas ...
- SharePoint 2007 文档库中的文档添加评论功能
背景:接到一个项目,要求文档管理,当然文档库就可以了,但是要求文档需要大家去读,读完以后还可以发表评论,这Moss貌似就有点困难了.和同事一起合计,想来想去也没有太好的办法,后来想到传统开发,两个表的 ...
- rails应用ajax之二:使用rails自身支持
考虑另一种情况: 1. 页面上半部分显示当前的所有用户,页面下半部分是输入新用户的界面: 2. 每当输入新用户时,页面上半部分会动态更新新加用户的内容: 我们还是用ajax实现,不过这次用rails内 ...
- ubuntu下ruby文件执行蛋疼的一个问题
ubuntu下面用sublime打开非常简单的一段代码(其实不算代码,因为没有实际语句): #!/usr/bin/ruby 在shell下加入x权限:chmod u+x doit.rb,然后运行 ./ ...
- 关于jasperreport对应java打印机的解决方案
对于jasperreport打印这个功能,遇到了一大堆问题,也只能一点一点解决我: 1.现在我用的是jasperreport.jar是4.6版本. (1).因为网上查到:6.0以上版本已经不再支持ja ...
- 简单验证码的识别:Bitmap类的使用
验证码的智能识别是一项比较复杂的工作,甚至需要掌握点图像学的知识. 当然对于写程序的来说不用那么深入,只需要掌握几个常规步骤就行了. 验证码图像识别步骤:1.获取图像 2.清除边框 3.灰度处理 4. ...
- JeeSite数据分页与翻页
本文章介绍的是JeeSite开源项目二次开发时的一些笔记,对于没有使用过JeeSite的可以不用往下看了,因为下面的代码是跟JeeSite二次开发相关的代码,不做JeeSite的二次开发,以下代码对您 ...
- Yii2快速总结
1.项目目录 后面的总结都是基于这个项目目录,注意:这个Yii2框架的basic版本原始的目录结构,未作任何更改. 2.新建控制器以及视图 controllers这个目录下的SiteControlle ...
- LeetCode_图像渲染
题目: 有一幅以二维整数数组表示的图画,每一个整数表示该图画的像素值大小,数值在 0 到 65535 之间. 给你一个坐标 (sr, sc) 表示图像渲染开始的像素值(行 ,列)和一个新的颜色值 ne ...
- vue.js常见的报错信息及其解决方法的记录
1.Vue packages version mismatch 翻译:vue包版本匹配错误 报错样例: 报错原因:通常出现于一些依赖库的更新或者安装新的依赖库之后(可以认为npm update已经成为 ...