BOM系列第一篇之定時(shí)器setTimeout和setInterval
setTimeout()
setTimeout()方法用來(lái)指定某個(gè)函數(shù)或字符串在指定的毫秒數(shù)之后執(zhí)行。它返回一個(gè)整數(shù),表示定時(shí)器的編號(hào),這個(gè)值可以傳遞給clearTimeout()用于取消這個(gè)函數(shù)的執(zhí)行
以下代碼中,控制臺(tái)先輸出0,大概過(guò)1000ms即1s后,輸出定時(shí)器setTimeout()方法的返回值1
var Timer = setTimeout(function(){ console.log(Timer); },1000); console.log(0);
也可以寫(xiě)成字符串參數(shù)的形式,由于這種形式會(huì)造成javascript引擎兩次解析,降低性能,故不建議使用
var Timer = setTimeout('console.log(Timer);',1000); console.log(0);
如果省略setTimeout的第二個(gè)參數(shù),則該參數(shù)默認(rèn)為0
以下代碼中,控制臺(tái)出現(xiàn)0和1,但是0卻在前面,后面會(huì)解釋這個(gè)疑問(wèn)
var Timer = setTimeout(function(){ console.log(Timer); }); console.log(0);
實(shí)際上,除了前兩個(gè)參數(shù),setTimeout()方法還允許添加更多的參數(shù),它們將被傳入定時(shí)器中的函數(shù)中
以下代碼中,控制臺(tái)大概過(guò)1000ms即1s后,輸出2,而IE9-瀏覽器只允許setTimeout有兩個(gè)參數(shù),不支持更多的參數(shù),會(huì)在控制臺(tái)輸出NaN
setTimeout(function(a,b){ console.log(a+b); },1000,1,1);
可以使用IIFE傳參來(lái)兼容IE9-瀏覽器的函數(shù)傳參
setTimeout((function(a,b){ return function(){ console.log(a+b); } })(1,1),1000);
或者將函數(shù)寫(xiě)在定時(shí)器外面,然后函數(shù)在定時(shí)器中的匿名函數(shù)中帶參數(shù)調(diào)用
function test(a,b){ console.log(a+b); } setTimeout(function(){ test(1,1); },1000);
this指向
在this機(jī)制系列已經(jīng)詳細(xì)介紹過(guò)this指向的4種綁定規(guī)則,由于定時(shí)器中的this存在隱式丟失的情況,且極易出錯(cuò),因此在這里再次進(jìn)行說(shuō)明
var a = 0; function foo(){ console.log(this.a); }; var obj = { a : 2, foo:foo } setTimeout(obj.foo,100);//0 //等價(jià)于 var a = 0; setTimeout(function foo(){ console.log(this.a); },100);//0
若想獲得obj對(duì)象中的a屬性值,可以將obj.foo函數(shù)放置在定時(shí)器中的匿名函數(shù)中進(jìn)行隱式綁定
var a = 0; function foo(){ console.log(this.a); }; var obj = { a : 2, foo:foo } setTimeout(function(){ obj.foo(); },100);//2
或者也可以使用bind方法將foo()方法的this綁定到obj上
var a = 0; function foo(){ console.log(this.a); }; var obj = { a : 2, foo:foo } setTimeout(obj.foo.bind(obj),100);//2
clearTimeout()
setTimeout函數(shù)返回一個(gè)表示計(jì)數(shù)器編號(hào)的整數(shù)值,將該整數(shù)傳入clearTimeout函數(shù),取消對(duì)應(yīng)的定時(shí)器
//過(guò)100ms后,控制臺(tái)輸出setTimeout()方法的返回值1 var Timer = setTimeout(function(){ console.log(Timer); },100);
于是可以利用這個(gè)值來(lái)取消對(duì)應(yīng)的定時(shí)器
var Timer = setTimeout(function(){ console.log(Timer); },100); clearTimeout(Timer);
或者直接使用返回值作為參數(shù)
var Timer = setTimeout(function(){ console.log(Timer); },100); clearTimeout(1);
一般來(lái)說(shuō),setTimeout返回的整數(shù)值是連續(xù)的,也就是說(shuō),第二個(gè)setTimeout方法返回的整數(shù)值比第一個(gè)的整數(shù)值大1
//控制臺(tái)輸出1、2、3 var Timer1 = setTimeout(function(){ console.log(Timer1); },100); var Timer2 = setTimeout(function(){ console.log(Timer2); },100); var Timer3 = setTimeout(function(){ console.log(Timer3); },100);
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í)間間隔是4毫秒;setInterval的最短間隔時(shí)間是10毫秒,也就是說(shuō),小于10毫秒的時(shí)間間隔會(huì)被調(diào)整到10毫秒
大多數(shù)電腦顯示器的刷新頻率是60HZ,大概相當(dāng)于每秒鐘重繪60次。因此,最平滑的動(dòng)畫(huà)效的最佳循環(huán)間隔是1000ms/60,約等于16.6ms
為了節(jié)電,對(duì)于那些不處于當(dāng)前窗口的頁(yè)面,瀏覽器會(huì)將時(shí)間間隔擴(kuò)大到1000毫秒。另外,如果筆記本電腦處于電池供電狀態(tài),Chrome和IE 9以上的版本,會(huì)將時(shí)間間隔切換到系統(tǒng)定時(shí)器,大約是16.6毫秒
運(yùn)行機(jī)制
下面來(lái)解釋前面部分遺留的疑問(wèn),為什么下面代碼的控制臺(tái)結(jié)果中,0出現(xiàn)在1的前面呢?
setTimeout(function(){ console.log(1); }); console.log(0);
實(shí)際上,把setTimeout的第二個(gè)參數(shù)設(shè)置為0s,并不是立即執(zhí)行函數(shù)的意思,只是把函數(shù)放入代碼隊(duì)列
在下面這個(gè)例子中,給一個(gè)按鈕btn設(shè)置了一個(gè)事件處理程序。事件處理程序設(shè)置了一個(gè)250ms后調(diào)用的定時(shí)器。點(diǎn)擊該按鈕后,首先將onclick事件處理程序加入隊(duì)列。該程序執(zhí)行后才設(shè)置定時(shí)器,再有250ms后,指定的代碼才被添加到隊(duì)列中等待執(zhí)行
btn.onclick = function(){ setTimeout(function(){ console.log(1); },250); }
如果上面代碼中的onclick事件處理程序執(zhí)行了300ms,那么定時(shí)器的代碼至少要在定時(shí)器設(shè)置之后的300ms后才會(huì)被執(zhí)行。隊(duì)列中所有的代碼都要等到JavaScript進(jìn)程空閑之后才能執(zhí)行,而不管它們是如何添加到隊(duì)列中的
如圖所示,盡管在255ms處添加了定時(shí)器代碼,但這時(shí)候還不能執(zhí)行,因?yàn)閛nclick事件處理程序仍在運(yùn)行。定時(shí)器代碼最早能執(zhí)行的時(shí)機(jī)是在300ms處,即onclick事件處理程序結(jié)束之后
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)題:1、某些間隔被跳過(guò);2、多個(gè)定時(shí)器的代碼執(zhí)行之間的間隔可能比預(yù)期的小
假設(shè),某個(gè)onclick事件處理程序使用serInterval()設(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()定時(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>
應(yīng)用
使用定時(shí)器來(lái)調(diào)整事件發(fā)生順序
【1】網(wǎng)頁(yè)開(kāi)發(fā)中,某個(gè)事件先發(fā)生在子元素,然后冒泡到父元素,即子元素的事件回調(diào)函數(shù),會(huì)早于父元素的事件回調(diào)函數(shù)觸發(fā)。如果,我們先讓父元素的事件回調(diào)函數(shù)先發(fā)生,就要用到setTimeout(f, 0)
正常情況下,點(diǎn)擊div元素,先彈出0,再?gòu)棾?
<div id="myDiv" style="height: 100px;width: 100px;background-color: pink;"></div> <script> myDiv.onclick = function(){ alert(0); } document.onclick = function(){ alert(1); } </script>
如果進(jìn)行想讓document的onclick事件先發(fā)生,即點(diǎn)擊div元素,先彈出1,再?gòu)棾?。則進(jìn)行如下設(shè)置
<div id="myDiv" style="height: 100px;width: 100px;background-color: pink;"></div> <script> myDiv.onclick = function(){ setTimeout(function(){ alert(0); }) } document.onclick = function(){ alert(1); } </script>
【2】用戶(hù)自定義的回調(diào)函數(shù),通常在瀏覽器的默認(rèn)動(dòng)作之前觸發(fā)。比如,用戶(hù)在輸入框輸入文本,keypress事件會(huì)在瀏覽器接收文本之前觸發(fā)。因此,下面的回調(diào)函數(shù)是達(dá)不到目的
<input type="text" id="myInput"> <script> myInput.onkeypress = function(event) { this.value = this.value.toUpperCase(); } </script>
上面代碼想在用戶(hù)輸入文本后,立即將字符轉(zhuǎn)為大寫(xiě)。但是實(shí)際上,它只能將上一個(gè)字符轉(zhuǎn)為大寫(xiě),因?yàn)闉g覽器此時(shí)還沒(méi)接收到文本,所以this.value取不到最新輸入的那個(gè)字符
只有用setTimeout改寫(xiě),上面的代碼才能發(fā)揮作用
<input type="text" id="myInput"> <script> myInput.onkeypress = function(event) { setTimeout(function(){ myInput.value = myInput.value.toUpperCase(); }); } </script>
代碼到此結(jié)束。下篇給大家介紹
BOM系列第二篇之定時(shí)器requestAnimationFrame
BOM系列第三篇之定時(shí)器應(yīng)用(時(shí)鐘、倒計(jì)時(shí)、秒表和鬧鐘)
以上所述是小編給大家介紹的BOM系列第一篇之定時(shí)器setTimeout和setInterval ,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
- js基于setTimeout與setInterval實(shí)現(xiàn)多線程
- 深入理解setTimeout函數(shù)和setInterval函數(shù)
- 快速掌握Node.js中setTimeout和setInterval的使用方法
- JavaScript中setTimeout和setInterval函數(shù)的傳參及調(diào)用
- JavaScript中SetInterval與setTimeout的用法詳解
- javascript中SetInterval與setTimeout的定時(shí)器用法
- Javascript中setTimeOut和setInterval的定時(shí)器用法
- JavaScript中停止執(zhí)行setInterval和setTimeout事件的方法
- js中的setInterval和setTimeout使用實(shí)例
- JavaScript SetInterval與setTimeout使用方法詳解
- setTimeout和setInterval的深入理解
- BOM系列第二篇之定時(shí)器requestAnimationFrame
- BOM系列第三篇之定時(shí)器應(yīng)用(時(shí)鐘、倒計(jì)時(shí)、秒表和鬧鐘)
相關(guān)文章
javascript實(shí)現(xiàn)數(shù)組去重的多種方法
這篇文章主要為大家詳細(xì)介紹了javascript實(shí)現(xiàn)數(shù)組去重的多種方法,感興趣的小伙伴們可以參考一下2016-03-03純js網(wǎng)頁(yè)畫(huà)板(Graphics)類(lèi)簡(jiǎn)介及實(shí)現(xiàn)代碼
今天需要在網(wǎng)頁(yè)上畫(huà)一個(gè)圖譜,想到用JS,經(jīng)過(guò)學(xué)習(xí),和網(wǎng)上搜索,經(jīng)過(guò)整理優(yōu)化得到下面代碼,注意不是用HTML5的canvas,而是用的純js,需要了解的朋友可以參考下2012-12-12js對(duì)數(shù)組中的數(shù)字從小到大排序?qū)崿F(xiàn)代碼
對(duì)數(shù)組中的數(shù)字從小到大排序,很多時(shí)候需要用的多,需要的朋友可以參考下2012-09-09微信小程序picker組件兩列關(guān)聯(lián)使用方式
這篇文章主要介紹了微信小程序picker組件兩列關(guān)聯(lián)使用方式,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10bootstrap fileinput實(shí)現(xiàn)文件上傳功能
這篇文章主要為大家詳細(xì)介紹了bootstrap fileinput實(shí)現(xiàn)文件上傳功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08javascript移動(dòng)設(shè)備Web開(kāi)發(fā)中對(duì)touch事件的封裝實(shí)例
這篇文章主要介紹了javascript移動(dòng)設(shè)備Web開(kāi)發(fā)中對(duì)touch事件的封裝實(shí)例,分別對(duì)tap事件、doubleTap事件、longTap事件、swipe事件做了封裝,需要的朋友可以參考下2014-06-06JavaScript實(shí)現(xiàn)全選和全不選操作
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)全選和全不選操作,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09