两年前刚接触前端时, 有这么一个例子.
var message = [1,2,3];
for(var i=0;i
console.log(message[i]);
},i*1500)
}
按照当时的想法, 输出结果不肯定是 1 2 3吗?
但是当,输出了 3个 undefined 时, 一脸懵逼的 我(or you) 是不是觉得 肯定是电脑huai了?哈哈
那问题到底是出在了哪呢?
看到好多借用这样的经典例子,去解释 var 的作用域.(其作用域是函数内)
ps: 如果你不知道 (其作用域是函数内) 这句话的意思, 那么在你接触ES6的时候,肯定听过 代码块的 概念.
感兴趣的 可以去了解一下 var ; let; const 三者的区别.
当然,借助这个例子,也解释了 var 的作用域的相关知识, 但是 你真的了解了这段代码吗?
反正我当时是不了解的! 单从作用域的角度,根本就解释不通! 反正不了解那就对了,因为很少有例子去提及 队列 线程!
同样的上一段代码.
var message = [1,2,3];
for(var i=0;i
}
这时候输出的 1 , 2 , 3 没毛病吧,也符合初学者的认知. 但是你想说,what? 为啥加个 setTimeout 就不行了呢?
然后还扯到 什么var 作用域的问题?
在这里, setTimeout 其实就是模拟了一个异步线程!异步线程!异步线程!
for(var i=0;i
}
计算机的计算是每秒百万级的运算. 当for循环中的 i 判断 i< length , 然后++ 时, 异步操作 可能并没有执行完成,
所以, i 继续++. 当然 当i++ 结束时, 异步操作也有可能是 没有结束的. (除非 你这个length的长度是几百万,循环的时间 花费 比异步操作还长)
SO, 当终于轮到执行异步操作中的 输出语句 console.log(message[i]) 时. i的值,其实已经是 3.
然后 执行了 3次 console.log(message[3]);
为了 更形象的让大家理解, 我就举个例子, 括号中的时间 代表这个指令运行时的时间.
执行队列就是:
for 循环(0.1秒) ==>异步输出语句1(0+0.4秒时执行)
for 循环 (0.2秒) ==>异步输出语句2(1.5秒+0.4秒时执行)
for 循环 (0.3秒) ==>异步输出语句3(3秒+0.4秒时执行)
异步 i=0时, setTimeout 延时 明明是 0 * 1.5 不应该是立即执行的吗? 然而,还是那句话,计算机的计算是每秒百万级的,同时计算机现在都是多核进行运算的, 所以, 至于哪个线程会 先执行完?计算机的线程是如何调配的? 这都是 是有很大偶然性滴!(开发中,考虑到性能优化的准则,有一项就是线程优化? 保持多少条线程异步执行才能更高效?感兴趣的请自行搜索相关知识)
这是我的这段测试代码:
var message = [1,2,3];
for(i=0;i
var end = new Date().getTime();//结束时间
console.log("同步"+(end - start)+"ms");
setTimeout(function(){
var end1 = new Date().getTime();//结束时间
console.log("异步"+(end1 - start)+"ms");
},i*1500)
}
同步0ms
同步0ms
同步0ms
异步1ms
异步1502ms
异步3005ms
注意看这个执行顺序! 同步0ms ,异步1ms 这个就是所说的偶然性. 感兴趣的可以去深入了解下计算机线程; 栈 ;队列的概念, 以及 同步异步 的相关知识. 这不是今天要说的重点,所以就不过多阐述.
言归正传: 既然 异步执行时, 我用了var 定义的变量. 那么for循环取值时 ,收到了影响.
那有什么好的解决方法吗?
答案肯定是有的啊!
一: 使用forEach 代替 for循环
messages.forEach(function (message, i) {
setTimeout(function () {
cat.say(message);
}, i * 1500);
});
同样也输出了 1 , 2, 3
二: 涉及ES6,使用 let 定义 的变量
我们只需要将for循环中的 var i =0 ; 替换成 let i=0;
for(let i=0;i
console.log(message[i]);
},i*1500)
}
运算结果也是 1, 2, 3
形如for (let x...)的循环在每次迭代时都为x创建新的绑定。let声明的变量直到控制流到达该变量被定义的代码行时才会被装载; 这里只说明了ES6的处理机制,深入的请自行学习.
然后这时候 带着你的好奇与疑问 再去 学es6 相关知识点的时候,相信会有事半功倍的效果,也会加深你的理解.