本文實(shí)例分析了js中setTimeout()與clearTimeout()用法,具體分析如下:
setTimeout() 方法用于在指定的毫秒數(shù)后調(diào)用函數(shù)或計(jì)算表達(dá)式.
clearTimeout() 方法可取消由 setTimeout() 方法設(shè)置的 timeout.
<input type = text id = aaa > <input type = button value = stop id = bb onclick = bb()> <script> <!-- var iTime function aa() { aaa.value += "!"; iTime=setTimeout("aa()",600); } function bb() { if (iTime !="") clearTimeout(iTime); } aa() --> </script>
setTimeout的標(biāo)準(zhǔn)語法是: setTimeout(表達(dá)式,時(shí)間(毫秒)) 兩個(gè)參數(shù). 在這里著重記下第一個(gè)參數(shù)是一個(gè) function時(shí)的調(diào)用,假設(shè)是一個(gè)函數(shù). 1.函數(shù)無參: function alertV(){ alert("000"); } 當(dāng)?shù)谝粋€(gè)參數(shù)不加引號(hào)("" 或 '')時(shí),延遲一秒: setTimeout(alertV,1000); 當(dāng)?shù)谝粋€(gè)參數(shù)加上又引號(hào)時(shí),延遲一秒: setTimeout("alertV()",1000); 2. 函數(shù)有參: function alertV(event){ alert("keyCode="+event.keyCode); } 此時(shí)應(yīng)設(shè)置成: setTimeout(function(){alertV(event);},1000); 不然會(huì)提示參數(shù)未定義.
setTimeout(function () { $("#id").html(datastr); }, 1000);
jquery的通過delay實(shí)現(xiàn),例如
$("#id").delay(1000).html(datastr);
setTimeout('yourFunction()',5000); 5秒后執(zhí)行yourFunction(),只執(zhí)行一次
setInterval('yourFunction()',5000); 每隔5秒執(zhí)行一次u
如果在yourFunction()中再次調(diào)用了setTimeout('yourFunction()',5000),可以完成類似于
setInterval('yourFunction()',5000)的功能
javascript定時(shí)器工作原理是一個(gè)重要的基礎(chǔ)知識(shí)點(diǎn)。因?yàn)槎〞r(shí)器在單線程中工作,它們表現(xiàn)出的行為很直觀。我們?cè)撊绾蝿?chuàng)建和維護(hù)定時(shí)器呢?要從如下三個(gè)函數(shù)(都是定義在全局作用域,在瀏覽器中就是window的方法)說起:
var id=setTimeout(fn,delay);-初始化一個(gè)只執(zhí)行一次的定時(shí)器,這個(gè)定時(shí)器會(huì)在指定的時(shí)間延遲delay之后調(diào)用函數(shù)fn,該setTimeout函數(shù)返回定時(shí)器的唯一id,我們可以通過這個(gè)id來取消定時(shí)器的執(zhí)行。
var id=setInvertal(fn,delay);-與setTimeout類似,只是它會(huì)以delay為周期,反復(fù)調(diào)用函數(shù)fn,直到我們通過id取消該定時(shí)器。
clearInterval(id),clearTimeout(id),;-這兩個(gè)函數(shù)接受定時(shí)器的id(例如我們上面提到的兩個(gè)函數(shù)產(chǎn)生的定時(shí)器id),并停止對(duì)定時(shí)器中指定函數(shù)的調(diào)用。
要深入理解定時(shí)器工作原理,我們需要探索一個(gè)重要的概念:定時(shí)器指定的延遲時(shí)間并不能得到保證。在瀏覽器中,因?yàn)樗械膉avascript代碼都運(yùn)行在單一線程之中,異步事件(如鼠標(biāo)點(diǎn)擊,定時(shí)器)只有在他們被觸發(fā)的時(shí)候他們的回調(diào)才有機(jī)會(huì)得以執(zhí)行。我們可以用下圖說明:
圖中包含大量的信息,吸收并理解這些信息,能幫助我們領(lǐng)悟“異步的javascript代碼是如何工作的”。這個(gè)圖是一維的,垂直方向是時(shí)間,以毫秒為單位。藍(lán)色的盒子代表正在執(zhí)行的javascript代碼所占時(shí)間片段。例如 第一個(gè)javascript塊執(zhí)行時(shí)間約18ms,第二個(gè)鼠標(biāo)點(diǎn)擊塊執(zhí)行了約11ms,其他塊類似。
因?yàn)閱尉€程的緣故,在同一時(shí)間只能執(zhí)行一條javascript代碼,每一個(gè)代碼塊(藍(lán)色盒子)都會(huì)阻塞其他異步事件的執(zhí)行。這就意味著,當(dāng)一個(gè)異步事件發(fā)生的時(shí)候(例如鼠標(biāo)點(diǎn)擊,定時(shí)器觸發(fā),一個(gè)XMLHttpRequest 請(qǐng)求完成),它進(jìn)入了代碼的執(zhí)行隊(duì)列,執(zhí)行線程空閑時(shí)會(huì)依照該執(zhí)行隊(duì)列中順序依次執(zhí)行代碼。(如何將異步事件加入隊(duì)列,不同瀏覽器,他們的實(shí)現(xiàn)可能有所差異,所以這里我們將其簡單化)。
開始的時(shí)候,在Javascript代碼塊(第一個(gè)盒子),初始化了兩個(gè)定時(shí)器,一個(gè)10ms延遲的setTimeout 和10ms的setInterval。這些定時(shí)器可能會(huì)在我們第一個(gè)代碼塊執(zhí)行結(jié)束之前就觸發(fā),這取決于定時(shí)器在第一個(gè)代碼塊中啟動(dòng)的位置和時(shí)間。注意,定時(shí)器雖然觸發(fā)了,但是并不會(huì)立即執(zhí)行,它只是把需要延遲執(zhí)行的函數(shù)加入了執(zhí)行隊(duì)列,在線程的某一個(gè)可用的時(shí)間點(diǎn),這個(gè)函數(shù)就能夠得到執(zhí)行。
當(dāng)?shù)谝粋€(gè)Javascript代碼初始化塊執(zhí)行結(jié)束,瀏覽器立即提出一個(gè)問題:誰在等待著被執(zhí)行? 在這個(gè)案例中鼠標(biāo)點(diǎn)擊時(shí)間的處理程序和一個(gè)定時(shí)器(setTimeout)都在等待。瀏覽器選擇一個(gè)并執(zhí)行(這里是鼠標(biāo)點(diǎn)擊事件的處理程序)。定時(shí)器就需要等待下一個(gè)可用時(shí)間來執(zhí)行。
需要注意的是當(dāng)鼠標(biāo)點(diǎn)擊事件處理程序執(zhí)行的時(shí)候,第一個(gè)interval定時(shí)器觸發(fā)了。和timeout定時(shí)器一樣,他的回調(diào)函數(shù)被加入了執(zhí)行隊(duì)列,等待執(zhí)行。然而,還需要注意到當(dāng)interval定時(shí)器再次觸發(fā),這個(gè)時(shí)候timeout定時(shí)器的回調(diào)函數(shù)正在執(zhí)行,此時(shí)這個(gè)interval的觸發(fā)被放棄了。假想(瀏覽器不這樣做),在一個(gè)占用時(shí)間很多的初始化定時(shí)器的代碼塊中,所有的interval觸發(fā)都把回調(diào)加入執(zhí)行隊(duì)列,當(dāng)初始化代碼塊結(jié)束后,執(zhí)行隊(duì)列中已經(jīng)累加了大量的定時(shí)器回調(diào)函數(shù),結(jié)果就會(huì)出現(xiàn)大量的interval回調(diào)函數(shù)無間隔的執(zhí)行,直到該執(zhí)行隊(duì)列清空。所以瀏覽器在講一個(gè)interval回調(diào)加入執(zhí)行隊(duì)列前,會(huì)檢查執(zhí)行隊(duì)列,如果其中存在尚未執(zhí)行的interval回調(diào)那么就等待,直到當(dāng)前執(zhí)行隊(duì)列中沒有相應(yīng)interval的回調(diào)以后才會(huì)繼續(xù)入隊(duì)interval回調(diào)。
事實(shí)上,如圖,我們看見在第一個(gè)Interval的回調(diào)執(zhí)行的時(shí)候(之前進(jìn)入執(zhí)行隊(duì)列),第三個(gè)interval觸發(fā)了,這想我們展示一個(gè)重要的現(xiàn)象:Interval不關(guān)心當(dāng)前正在執(zhí)行的代碼,他們會(huì)不加選擇的添加回調(diào)到執(zhí)行隊(duì)列,盡管這意味著兩個(gè)interval回調(diào)函數(shù)執(zhí)行的時(shí)間間隔被犧牲。這里第一個(gè)interval回調(diào)執(zhí)行結(jié)束后,緊跟著第三個(gè)interval的回調(diào)馬上得到執(zhí)行,中間沒有印象中應(yīng)該有的10ms間隔。
最終,在第三個(gè)interval的回調(diào)執(zhí)行結(jié)束后,我們看見執(zhí)行隊(duì)列中沒有等待javascript引擎執(zhí)行的代碼,這就意味著,瀏覽器現(xiàn)在等待新的異步事件的發(fā)生,在50ms的刻度處interval再次觸發(fā),此時(shí)沒有什么會(huì)阻塞javascript引擎,這個(gè)interval回調(diào)會(huì)立即執(zhí)行。
讓我們看一個(gè)例子來闡明,setInterval和setTimeout的不同,
setTimeout(function(){
/* Some long block of code... */
setTimeout(arguments.callee, 10);
}, 10);
setInterval(function(){
/* Some long block of code... */
}, 10);
看第一眼,會(huì)覺得這兩段代碼功能相同,實(shí)際上,他們是不同的。
需要注意到,setTimeout的回調(diào)函數(shù)的執(zhí)行總是保證了至少10ms的間隔(與上一個(gè)回調(diào)的執(zhí)行相比,實(shí)際執(zhí)行時(shí),這個(gè)間隔可能變長,但是不可能更少),但是setInterval會(huì)嘗試每隔10ms執(zhí)行一次回調(diào),不管上一個(gè)回調(diào)函數(shù)時(shí)候已經(jīng)執(zhí)行完畢。(很多類庫的動(dòng)畫都是使用的setTimeout實(shí)現(xiàn))
這里我們學(xué)到很多,總結(jié)一下:
javascript引擎是單線程的,會(huì)迫使異步事件進(jìn)入執(zhí)行隊(duì)列,等待執(zhí)行。
setTimeout和setInterval在執(zhí)行異步代碼時(shí)從根本上是有所不同的。
如果一個(gè)定時(shí)器事件被阻塞,使得它不能立即執(zhí)行,那么它會(huì)被延遲,直到下一個(gè)可能的時(shí)間點(diǎn),才被執(zhí)行(這可能比你指定的delay時(shí)間要長)
Interval的回調(diào)有可能‘背靠背’無間隔的執(zhí)行,這種情況是說interval的回調(diào)函數(shù)的執(zhí)行時(shí)間比你指定的delay時(shí)間還要長
這些都是構(gòu)建javascript應(yīng)用程序非常重要的知識(shí)。了解javascript Engine是如何工作的,特別存在大量的異步事件發(fā)生,為構(gòu)建高級(jí)應(yīng)用程序代碼打下基礎(chǔ)。
如對(duì)本文有疑問,請(qǐng)?zhí)峤坏浇涣髡搲?,廣大熱心網(wǎng)友會(huì)為你解答??! 點(diǎn)擊進(jìn)入論壇