js setTimeout和for循环搭配使用时变量的问题

352 阅读1分钟

1 setTimeout(func,time)函数运行机制

setTimeout(func,time)是在time(毫秒单位)时间后执行func函数。浏览器引擎按顺序执行程序,遇到setTimeout会将func函数放到执行队列中,等到主程序执行完毕之后,才开始从执行队列(队列中可能有多个待执行的func函数)中按照time延时时间的先后顺序取出来func并执行。即使time=0,也会等主程序运行完之后,才会执行

    console.log(1)
    setTimeout(()=>{
        console.log(2)
    },0)
    console.log(3);
    setTimeout(()=>{
        console.log(4)
    },100)
    console.log(5)

输出1,3,5,2,4

2 for循环和setTimeout搭配使用时出现的问题

    for(var i=0;i<5;i++){
        setTimeout(()=>{
            console.log(i)
        },1000)
    }

1s之后,同时输出 5 个 5。

因为 for 循环会先执行完(同步优先于异步优先于回调),这时五个 setTimeout 的回调全部塞入了事件队列中,然后 1 秒后一起执行了。

3 解决办法

3.1 let块级作用域

for (let i = 0; i < 5; i++) { 
  setTimeout(function() { 
   console.log(i); 
 }, 1000 * i); 
}

1s后,输出0,1,2,3,4

3.2 闭包包裹

for (var i = 0; i < 5; i++) { 
 (function(i) { 
  setTimeout(function() { 
   console.log(i); 
  }, 1000); 
 })(i); 
}

1s后,输出0,1,2,3,4

3.3 传入闭包做为参数

3.3.1 传入参数
for (var i = 0; i < 5; i++) { 
 setTimeout((function(i) { 
  console.log(i); 
 })(i), i * 1000); 
}

立刻输出0,1,2,3,4

3.3.2 不传参数
for (var i = 0; i < 5; i++) { 
 setTimeout((function() { 
  console.log(i); 
 })(), i * 1000); 
}

立刻输出0,1,2,3,4

4 setTimeout第三个参数

for(var i=0;i<5;i++) {
  setTimeout(function(i) {console.log(i)},0,i)
}
for(var i =0;i<5;i++){
    setTimeout((i)=>{
        console.log(i);
    },0,i)
}
a = function(i) {
    console.log(i)
}
for(var i =0;i<5;i++){
    setTimeout(a,1000,i)
}