setTimeout和for循环引发的常识错误

2017-04-14  本文已影响0人  physihan

标签(空格分隔): javascript


最近想要去实现一个定时函数,定时的去改变一个元素的opacity,从而实现淡入浅出的效果,我写出的代码是这样的

var pic=document.getElementById('picture')
for(var i=0;i<=10;i++){
    setTimeout(function(){
        pic.style.opacity=i*0.1
        console.log(i)
    },1000)
}

结果一直不变,在控制台console.log(i)发现i一直没变,每次输出都是11,想了想是因为setTimeout()函数是异步实现的,在开始回调函数的时候,for循环早已经结束了,而引用的i则是最后一次循环结束后i的值11。
那我就用闭包来保存i的值吧

for(var i=0;i<=10;i++){
(function(j){
    setTimeout(function(){
        pic.style.opacity=j*0.1
        console.log(j)
    },1000)
})(i)
}

试了一下,发现还是不行,这次console对了能正确输出i的值,但这不是我想要的啊,我要实现opacity定时改变,然而这个怎么是一秒就完成了?理想中的结果应该是隔一秒输出一个数啊,我在查阅一些资料以后发现,这已经不是闭包能解决的了,由于javascript的单线程的机制,settimeout的执行必然是在循环之后的,即使把倒计时时间设为0也是这样。

我又尝试了下不在循环里面写 setTimeout,结果也是这样

setTimeout(function () {
    console.log(1)
}, 3000);
setTimeout(function () {
    console.log(2)
}, 3000);
setTimeout(function () {
    console.log(3)
}, 3000);

结果是在3秒后连续输出了123,并没有停顿3秒,因为setTimeout这个倒计时函数的回调是异步执行的,这样for循环的问题就可以解释了,for循环执行了多次setTimeout函数,但是回调都是各自独立的,都是在1秒后执行回调函数,几乎在同时把我想要的那个元素的opacity设置了11次,自然是看不到“淡入”的效果了。看样子我是把setTimeout函数当成延时函数是不能这么写的了,那还有没有别的方法呢
方法肯定是有的,可以去尝试一下回调地狱

setTimeout(function(){
    console.log(1)
    setTimeout(function(){
        console.log(2)
        setTimeout(function(){
            console.log(3)
            ...
        },1000)
    },1000)
},1000)

这实际上就是递归调用自身,抽象一下

var makeInterval=function(){
    var times=0;
    var step=function(){
        console.log(times)
        times++
        if(times<10){
            setTimeout(step,1000)
        }
    }
    setTimeout(step,0)
}
makeInterval()

实际上还可以使用setInterval来写这段代码

var makeInterval=function(){
    var times=0;
    var timer=setInterval(function(){
        if(times==9){
            clearTimeout(timer)
        }
        console.log(times)
        times++
    },1000)
}
makeInterval()

关于使用setTimeout还是setIntervalstackoverflow上有解释,基本上是可以互相替换的,本人更加推荐使用setInterval,认为它更适合实现间隔的功能。
至此,已经解决了 for 循环的 bug,总结原因,还是自己对这个函数有点想当然,然而真正去写的时候才能发现问题,可能也有一些朋友会犯和我一样的错误,这里写出来和大家分享一下。

上一篇下一篇

猜你喜欢

热点阅读