標(biāo)簽(空格分隔): javascript
最近想要去實(shí)現(xiàn)一個(gè)定時(shí)函數(shù),定時(shí)的去改變一個(gè)元素的opacity
豌注,從而實(shí)現(xiàn)淡入淺出的效果伤塌,我寫出的代碼是這樣的
var pic=document.getElementById('picture')
for(var i=0;i<=10;i++){
setTimeout(function(){
pic.style.opacity=i*0.1
console.log(i)
},1000)
}
結(jié)果一直不變,在控制臺(tái)console.log(i)
發(fā)現(xiàn)i一直沒變幌羞,每次輸出都是11寸谜,想了想是因?yàn)?code>setTimeout()函數(shù)是異步實(shí)現(xiàn)的,在開始回調(diào)函數(shù)的時(shí)候属桦,for循環(huán)早已經(jīng)結(jié)束了熊痴,而引用的i則是最后一次循環(huán)結(jié)束后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)
}
試了一下聂宾,發(fā)現(xiàn)還是不行果善,這次console對(duì)了能正確輸出i的值,但這不是我想要的啊系谐,我要實(shí)現(xiàn)opacity
定時(shí)改變巾陕,然而這個(gè)怎么是一秒就完成了?理想中的結(jié)果應(yīng)該是隔一秒輸出一個(gè)數(shù)啊纪他,我在查閱一些資料以后發(fā)現(xiàn)鄙煤,這已經(jīng)不是閉包能解決的了,由于javascript的單線程的機(jī)制茶袒,settimeout
的執(zhí)行必然是在循環(huán)之后的梯刚,即使把倒計(jì)時(shí)時(shí)間設(shè)為0也是這樣。
我又嘗試了下不在循環(huán)里面寫 setTimeout
薪寓,結(jié)果也是這樣
setTimeout(function () {
console.log(1)
}, 3000);
setTimeout(function () {
console.log(2)
}, 3000);
setTimeout(function () {
console.log(3)
}, 3000);
結(jié)果是在3秒后連續(xù)輸出了123亡资,并沒有停頓3秒,因?yàn)?code>setTimeout這個(gè)倒計(jì)時(shí)函數(shù)的回調(diào)是異步執(zhí)行的向叉,這樣for循環(huán)的問題就可以解釋了锥腻,for循環(huán)執(zhí)行了多次setTimeout
函數(shù),但是回調(diào)都是各自獨(dú)立的母谎,都是在1秒后執(zhí)行回調(diào)函數(shù)瘦黑,幾乎在同時(shí)把我想要的那個(gè)元素的opacity設(shè)置了11次,自然是看不到“淡入”的效果了奇唤」╄担看樣子我是把setTimeout
函數(shù)當(dāng)成延時(shí)函數(shù)是不能這么寫的了,那還有沒有別的方法呢
方法肯定是有的冻记,可以去嘗試一下回調(diào)地獄
setTimeout(function(){
console.log(1)
setTimeout(function(){
console.log(2)
setTimeout(function(){
console.log(3)
...
},1000)
},1000)
},1000)
這實(shí)際上就是遞歸調(diào)用自身睡毒,抽象一下
var makeInterval=function(){
var times=0;
var step=function(){
console.log(times)
times++
if(times<10){
setTimeout(step,1000)
}
}
setTimeout(step,0)
}
makeInterval()
實(shí)際上還可以使用setInterval
來寫這段代碼
var makeInterval=function(){
var times=0;
var timer=setInterval(function(){
if(times==9){
clearTimeout(timer)
}
console.log(times)
times++
},1000)
}
makeInterval()
關(guān)于使用setTimeout
還是setInterval
在stackoverflow上有解釋,基本上是可以互相替換的冗栗,本人更加推薦使用setInterval演顾,認(rèn)為它更適合實(shí)現(xiàn)間隔的功能供搀。
至此,已經(jīng)解決了 for 循環(huán)的 bug钠至,總結(jié)原因葛虐,還是自己對(duì)這個(gè)函數(shù)有點(diǎn)想當(dāng)然,然而真正去寫的時(shí)候才能發(fā)現(xiàn)問題棉钧,可能也有一些朋友會(huì)犯和我一樣的錯(cuò)誤屿脐,這里寫出來和大家分享一下。