setInterval()
setInterval的用法與setTimeout完全一致,區(qū)別僅僅在于setInterval指定某個(gè)任務(wù)每隔一段時(shí)間就執(zhí)行一次,也就是無(wú)限次的定時(shí)執(zhí)行:
<button id="btn">0</button> <script> var timer = setInterval(function(){ btn.innerHTML = Number(btn.innerHTML) + 1; },1000); btn.onclick = function(){ clearInterval(timer); btn.innerHTML = 0; } </script>
HTML5標(biāo)準(zhǔn)規(guī)定,setTimeout的最短時(shí)間間隔是4ms;setInterval的最短間隔時(shí)間是10ms,也就是說(shuō),小于10ms的時(shí)間間隔會(huì)被調(diào)整到10ms。
大多數(shù)電腦顯示器的刷新頻率是60HZ,大概相當(dāng)于每秒鐘重繪60次。因此,最平滑的動(dòng)畫(huà)效的最佳循環(huán)間隔是1000ms/60,約等于16.6ms。
為了節(jié)電,對(duì)于那些不處于當(dāng)前窗口的頁(yè)面,瀏覽器會(huì)將時(shí)間間隔擴(kuò)大到1000ms。另外,如果筆記本電腦處于電池供電狀態(tài),Chrome和IE10+瀏覽器,會(huì)將時(shí)間間隔切換到系統(tǒng)定時(shí)器,大約是16.6ms。
setInterval()的問(wèn)題
使用setInterval()的問(wèn)題在于,定時(shí)器代碼可能在代碼再次被添加到隊(duì)列之前還沒(méi)有完成執(zhí)行,結(jié)果導(dǎo)致定時(shí)器代碼連續(xù)運(yùn)行好幾次,而之間沒(méi)有任何停頓。而JavaScript引擎對(duì)這個(gè)問(wèn)題的解決是:當(dāng)使用setInterval()時(shí),僅當(dāng)沒(méi)有該定時(shí)器的任何其他代碼實(shí)例時(shí),才將定時(shí)器代碼添加到隊(duì)列中。這確保了定時(shí)器代碼加入到隊(duì)列中的最小時(shí)間間隔為指定間隔。
但是,這樣會(huì)導(dǎo)致兩個(gè)問(wèn)題:
某些間隔被跳過(guò);
多個(gè)定時(shí)器的代碼執(zhí)行之間的間隔可能比預(yù)期的小
假設(shè),某個(gè)onclick事件處理程序使用setInterval()設(shè)置了200ms間隔的定時(shí)器。如果事件處理程序花了300ms多一點(diǎn)時(shí)間完成,同時(shí)定時(shí)器代碼也花了差不多的時(shí)間,就會(huì)同時(shí)出現(xiàn)跳過(guò)某間隔的情況:
例子中的第一個(gè)定時(shí)器是在205ms處添加到隊(duì)列中的,但是直到過(guò)了300ms處才能執(zhí)行。當(dāng)執(zhí)行這個(gè)定時(shí)器代碼時(shí),在405ms處又給隊(duì)列添加了另一個(gè)副本。在下一個(gè)間隔,即605ms處,第一個(gè)定時(shí)器代碼仍在運(yùn)行,同時(shí)在隊(duì)列中已經(jīng)有了一個(gè)定時(shí)器代碼的實(shí)例。結(jié)果是,在這個(gè)時(shí)間點(diǎn)上的定時(shí)器代碼不會(huì)被添加到隊(duì)列中
理解setTimeout和setInterval
例子中的第一個(gè)定時(shí)器是在205ms處添加到隊(duì)列中的,但是直到過(guò)了300ms處才能執(zhí)行。當(dāng)執(zhí)行這個(gè)定時(shí)器代碼時(shí),在405ms處又給隊(duì)列添加了另一個(gè)副本。在下一個(gè)間隔,即605ms處,第一個(gè)定時(shí)器代碼仍在運(yùn)行,同時(shí)在隊(duì)列中已經(jīng)有了一個(gè)定時(shí)器代碼的實(shí)例。結(jié)果是,在這個(gè)時(shí)間點(diǎn)上的定時(shí)器代碼不會(huì)被添加到隊(duì)列中
迭代setTimeout
為了避免setInterval()定時(shí)器的問(wèn)題,可以使用鏈?zhǔn)絪etTimeout()調(diào)用:
setTimeout(function fn(){ setTimeout(fn,interval); },interval);
這個(gè)模式鏈?zhǔn)秸{(diào)用了setTimeout(),每次函數(shù)執(zhí)行的時(shí)候都會(huì)創(chuàng)建一個(gè)新的定時(shí)器。第二個(gè)setTimeout()調(diào)用當(dāng)前執(zhí)行的函數(shù),并為其設(shè)置另外一個(gè)定時(shí)器。這樣做的好處是,在前一個(gè)定時(shí)器代碼執(zhí)行完之前,不會(huì)向隊(duì)列插入新的定時(shí)器代碼,確保不會(huì)有任何缺失的間隔。而且,它可以保證在下一次定時(shí)器代碼執(zhí)行之前,至少要等待指定的間隔,避免了連續(xù)的運(yùn)行
使用setInterval()
<div id="myDiv" style="height: 100px;width: 100px;background-color: pink;position:absolute;left:0;"></div> <script> myDiv.onclick = function(){ var timer = setInterval(function(){ if(parseInt(myDiv.style.left) > 200){ clearInterval(timer); return false; } myDiv.style.left = parseInt(myDiv.style.left) + 5 + 'px'; },16); } </script>
使用鏈?zhǔn)絪etTimeout()
<div id="myDiv" style="height: 100px;width: 100px;background-color: pink;position:absolute;left:0;"></div> <script> myDiv.onclick = function(){ setTimeout(function fn(){ if(parseInt(myDiv.style.left) <= 200){ setTimeout(fn,16); }else{ return false; } myDiv.style.left = parseInt(myDiv.style.left) + 5 + 'px'; },16); } </script>
setInterval 不同于setTimeout,setInterval會(huì)無(wú)限反復(fù)執(zhí)行,如果要讓setInterval停止執(zhí)行該怎么做呢?
只需要把setInterval()賦值給一個(gè)變量,然后clearInterval()這個(gè)變量即可停止。
例如:
var timesRun = 0; var interval = setInterval(function(){ timesRun += 1; if(timesRun === 60){ clearInterval(interval); } //do whatever here.. }, 2000); var startTime = new Date().getTime(); var interval = setInterval(function(){ if(new Date().getTime() - startTime > 60000){ clearInterval(interval); return; } //do whatever here.. }, 2000);
如上面的例子所示:
使用一個(gè)變量 var timer = setInterval(fun,2000);
將setInterval賦值給一個(gè)變量,要停止的時(shí)候,只需要使用clearInterval(timer);即可停止上面的這個(gè)每個(gè)兩秒循環(huán)執(zhí)行fun的這個(gè)函數(shù)了。
發(fā)送短信驗(yàn)證碼是一個(gè)非常常見(jiàn)的功能,
現(xiàn)在的需求是:
用戶(hù)點(diǎn)擊“獲取驗(yàn)證碼”的時(shí)候,請(qǐng)求后端接口,發(fā)送短信驗(yàn)證碼,
按鈕置灰不可點(diǎn),變成“重發(fā)(xx s)”, 40s后,出現(xiàn)“發(fā)送語(yǔ)音驗(yàn)證碼”按鈕,
60s后,“重發(fā)”按鈕再變成“獲取驗(yàn)證碼”
肯定是要用 setInterval() 了,但是這里邊就涉及到使用 clearInterval() 清除周期性執(zhí)行,
見(jiàn)示例:
<a class="c-right-btn btn-send-captcha">獲取驗(yàn)證碼</a> <a class="c-right-btn btn-send-captcha-disable" style="display:none;"></a>
window._timer = 60; var _send = setInterval(function(){ console.log(_timer); if(_timer > 0){ $(".btn-send-captcha").hide(); $(".btn-send-captcha-disable").show().text("重發(fā)(" + _timer + "s)"); _timer --; } if(_timer == 40){ $(".btn-send-voice").show(); } if(_timer <= 0){ $(".btn-send-captcha-disable").text("").hide(); $(".btn-send-captcha").show(); window.clearInterval(_send); _timer = 60; return false; } }, 1000);
如對(duì)本文有疑問(wèn),請(qǐng)?zhí)峤坏浇涣髡搲瑥V大熱心網(wǎng)友會(huì)為你解答??! 點(diǎn)擊進(jìn)入論壇