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 就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句。
我对阮一峰老师的话再具体说明一下,可能有些同学还不是特别理解。实际上我们调用了await,这时候await这条语句下面的语句已经不会执行了(内同),而是先给外层async函数返回了一个promise对象,await后面对应的应该也是一个promise对象只有该对象 resolve 掉,产生结果,await 那一行代码才算真正执行完,才继续往下走。(注意:await执行之后应该是一个resolve的结果而不是promise对象了)。
node.js后端开发-await在for循环中的应用
看一段后端项目中应用await的代码:
//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)