时间:17-04-25 栏目:ES6[ES2015], Javascript 作者:zongyan86 评论:0 点击: 8,568 次
本文标签: ES6 javascript 前端 闭包
这是js比较常见的一个题目:
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(new Date, i);
}, 1000);
}
结果为:
Tue Apr 25 2017 14:50:46 GMT+0800 (中国标准时间) 5 Tue Apr 25 2017 14:50:46 GMT+0800 (中国标准时间) 5 Tue Apr 25 2017 14:50:46 GMT+0800 (中国标准时间) 5 Tue Apr 25 2017 14:50:46 GMT+0800 (中国标准时间) 5 Tue Apr 25 2017 14:50:46 GMT+0800 (中国标准时间) 5
而不是我们所期望的
Tue Apr 25 2017 14:50:46 GMT+0800 (中国标准时间) 0 VM595:4 Tue Apr 25 2017 14:50:46 GMT+0800 (中国标准时间) 1 VM595:4 Tue Apr 25 2017 14:50:46 GMT+0800 (中国标准时间) 2 VM595:4 Tue Apr 25 2017 14:50:46 GMT+0800 (中国标准时间) 3 VM595:4 Tue Apr 25 2017 14:50:46 GMT+0800 (中国标准时间) 4
解决方法:
第一种:闭包
for (var i = 0; i < 5; i++) {
(function(j) { // j = i
setTimeout(function() {
console.log(new Date, j);
}, 1000);
})(i);
}
第二种:值类型传递
var output = function (i) {
setTimeout(function() {
console.log(new Date, i);
}, 1000);
};
for (var i = 0; i < 5; i++) {
output(i); // 这里传过去的 i 值被复制了
}
console.log(new Date, i);
第三种:es6 let
for (let i = 0; i < 5; i++) {
setTimeout(function() {
console.log(new Date, i);
}, 1000);
}
那如果要让0-4一秒一秒地输出来呢?
第一种:
for (var i = 0; i < 5; i++) {
(function(j) {
setTimeout(function() {
console.log(new Date, j);
}, 1000 * j); // 这里修改 0~4 的定时器时间
})(i);
}
setTimeout(function() { // 这里增加定时器,超时设置为 5 秒
console.log(new Date, i);
}, 1000 * i);
第二种:
const tasks = [];
for (var i = 0; i < 5; i++) { // 这里 i 的声明不能改成 let,如果要改该怎么做?
((j) => {
tasks.push(new Promise((resolve) => {
setTimeout(() => {
console.log(new Date, j);
resolve(); // 这里一定要 resolve,否则代码不会按预期 work
}, 1000 * j); // 定时器的超时时间逐步增加
}));
})(i);
}
Promise.all(tasks).then(() => {
setTimeout(() => {
console.log(new Date, i);
}, 1000); // 注意这里只需要把超时设置为 1 秒
});
第三种:
const tasks = []; // 这里存放异步操作的 Promise
const output = (i) => new Promise((resolve) => {
setTimeout(() => {
console.log(new Date, i);
resolve();
}, 1000 * i);
});
// 生成全部的异步操作
for (var i = 0; i < 5; i++) {
tasks.push(output(i));
}
// 异步操作完成之后,输出最后的 i
Promise.all(tasks).then(() => {
setTimeout(() => {
console.log(new Date, i);
}, 1000);
});
第四种:
// 模拟其他语言中的 sleep,实际上可以是任何异步操作
const sleep = (timeountMS) => new Promise((resolve) => {
setTimeout(resolve, timeountMS);
});
(async () => { // 声明即执行的 async 函数表达式
for (var i = 0; i < 5; i++) {
await sleep(1000);
console.log(new Date, i);
}
await sleep(1000);
console.log(new Date, i);
})();
声明: 本文由( zongyan86 )原创编译,转载请保留链接: 答案是丰富多彩的系列5:js实现循环setTimeout输出0,1,2,3,4