web前台入门到实战:JS中的for循环——你可能不知道的点。
提出问题
问题1:
看一段for循环的代码,大家先想一下执行结果是什么?
var arr = [2,4,6,8,10];var arrLength = arr.length;for (var i = 0; i < arrLength; i++) { setTimeout(function() { console.log(i); console.log(arr[i]); }, 2000);}
问题2:
for循环中出现多个异步函数(比方ajax请求,或者者node后台执行少量数据库操作或者文件操作),假如想要这些异步串行变为同步应该怎样做?
问题1处理与相关讲解
结果
预期结果
0 2 1 4 2 6 3 8 4 10
运行后的结果
5 undefined 5 undefined 5 undefined 5 undefined 5 undefined
产生结果的起因
setTimeout()函数回调属于异步任务,会出现在宏任务队列中,被压到了任务队列的最后,在这段代码应该是for循环这个同步任务执行完成后才会轮到它,所以for循环在遍历过程中i不断加1,直到i判断失败一次才中止,这时候i为5,也就是说空跑了5次循环。等到了setTimeOut预约的时间后就会执行在for遍历过程中公告的5个setTimeout。所以最终运行后会出现上面的结果,与预期结果不符。
正确执行的处理方案
1. 闭包,立即执行函数
想要得到预期的结果,第一种办法是使用闭包,在闭包函数内部形成了局部作用域,每循环一次,形成一个自己的局部作用域,不受外部变量变化的影响。代码如下:
专门建立的学习Q-q-u-n: 784783012 ,分享学习的方法和需要注意的小细节,不停升级最新的教程和学习技巧(从零基础开始到前台项目实战教程,学习工具,全栈开发学习路线以及规划)var arr = [2,4,6,8,10];var arrLength = arr.length;for (var i = 0; i < arrLength; i++) { (function(i) { setTimeout(function() { console.log('i是' + i); console.log('value是' + arr[i]); }, 2000); })(i);}
2. let
将代码中的var改成let,let非常适合用于 for循环内部的块级作用域。JS中的for循环体比较特殊,每次执行都是一个全新的独立的块作用域,用let公告的变量传入到 for循环体的作用域后,不会发生改变,不受外界的影响。
代码如下:
var arr = [2,4,6,8,10];var arrLength = arr.length;// i尽管在全局作用域公告,但是在for循环体局部作用域中使用的时候,变量会被固定,不受外界干扰。for (let i = 0; i < arrLength; i++) { (function(i) { setTimeout(function() { console.log('i是' + i); console.log('value是' + arr[i]); }, 2000); })(i);}
问题2处理与相关讲解
for循环中使用异步,在node.js后台开发或者者前台ajax请求的时候还是比较常见的。有多种处理方案
- 回调 callback 嵌套异步操作、再回调的方式
- Promise + then() 层层嵌套
- async和await
选择我个人认为最优秀的处理方式3async和await进行讲解。
async + await “外异内同”
例子:
假如要去将一批数据发送到服务器,只有前一批发送成功(即服务器返回成功的响应),才开始下一批数据的发送,否则终止发送。这就是一个典型的 “for 循环中存在相互依赖的异步操作” 的例子
例子对应伪代码:
async function task () { for (let val of [1, 2, 3, 4]) { // await 是要等待响应的 let result = await send(val); if (!result) { break; } }}task();
伪代码中使用await之后,实现了异步变成同步的转化,只有for循环中当次对应的发送请求完成且获取结果,才会继续往下执行。
await几点说明:
- await执行的那一行语句是同步的。
- async函数执行后,总是返回一个promise对象,可以了解为这个函数是一个异步函数(外异)但是———————-引用阮一峰老师书中一句话:
当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句。
node.js后台开发-await在for循环中的应用
看一段后台项目中应用await的代码:
专门建立的学习Q-q-u-n: 784783012 ,分享学习的方法和需要注意的小细节,不停升级最新的教程和学习技巧(从零基础开始到前台项目实战教程,学习工具,全栈开发学习路线以及规划)//dayResult是一个查询到的数组for (const item of dayResult) { //TODO 查询客户vip表 客户体验vip距离到期的客户列表 let userIds=await db.vip.findAll({ where:{ experience_time:{ '$lte':moment().subtract(15-item.day,'day').endOf('day') ,//获取四天前都0时0分秒 '$gte':moment().subtract(15-item.day,'day').startOf('day') ,//获取四天前都0时0分秒 }, vip_type:0 }, attributes:['user_id',Sequelize.literal(`'${item.id}' as notice_id`)], raw:true }); userNoticeRecord=userNoticeRecord.concat(userIds) }
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » web前台入门到实战:JS中的for循环——你可能不知道的点。