时间:17-04-25 栏目:ES6[ES2015], Javascript 作者:zongyan86 评论:0 点击: 7,832 次
本文标签: 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