淺談對(duì)于“不用setInterval,用setTimeout”的理解
JavaScript高級(jí)程序設(shè)計(jì)(第三版)(以下簡稱紅寶書)22.3高級(jí)定時(shí)器中詳細(xì)介紹了定時(shí)器setTimeout和setInterval,看完書后,深入理解了二者的區(qū)別,結(jié)合前輩們給我的建議“用setTimeout,不要用setInterval”,寫下此文,分析這個(gè)建議的合理性。
這兩個(gè)家伙看上去長得差不多,func是要執(zhí)行的函數(shù),interval是時(shí)間間隔。
setTimeout(func,interval) setInterval(func,interval)
關(guān)于時(shí)間間隔,紅寶書中這么說:
設(shè)定一個(gè) 150ms 后執(zhí)行的定時(shí)器不代表到了 150ms 代碼就立刻執(zhí)行,它表示代碼會(huì)在 150ms 后被加入到隊(duì)列中。如果在這個(gè)時(shí)間點(diǎn)上,隊(duì)列中沒有其他東西,那么這段代碼就會(huì)被執(zhí)行。
對(duì)于這個(gè)時(shí)間間隔的理解非常重要!步入正題,為何不用setInterval,因?yàn)樗赡軙?huì)帶來兩個(gè)問題:
- “丟幀”現(xiàn)象
- 不同定時(shí)器的代碼的執(zhí)行間隔比預(yù)期小
一圖勝千言,如下圖所示,讓我們跟著時(shí)間線看看這樣的問題怎么發(fā)生的。假定一個(gè)場景,在click事件中設(shè)置了setInterval(func,500),假設(shè)click事件和定時(shí)器內(nèi)函數(shù)的執(zhí)行時(shí)間都是1s,為了方便陳述,我把不同時(shí)間觸發(fā)的func取了不同的名字,實(shí)際上接下來的func1=func2=func3=func。在0s處觸發(fā)click事件,click事件執(zhí)行,在0.2s處觸發(fā)定時(shí)器,0.7s處第一個(gè)函數(shù)func1加入到事件隊(duì)列,但由于JS引擎是單線程的,click事件還在執(zhí)行,所以func1等待著,等到1s處,click事件執(zhí)行完畢,fun1才開始執(zhí)行。按照定時(shí)器的時(shí)間間隔,1.2s處第二個(gè)函數(shù)func2加入到事件隊(duì)列,但此時(shí)fun1正在執(zhí)行,所以func2只能等待。0.5s后,也就是1.7s處,第三個(gè)函數(shù)func理應(yīng)加入事件隊(duì)列,但是JS引擎做了一個(gè)事情:
當(dāng)使用 set Interval()時(shí),僅當(dāng)沒有該定時(shí)器的任何其他代碼實(shí)例時(shí),才將定時(shí)器代碼添加到隊(duì)列中。
在1.7s處,func1在執(zhí)行,func2在隊(duì)列里等待執(zhí)行,func2就是該定時(shí)器的代碼實(shí)例,按照J(rèn)S引擎的處理,func3不會(huì)加入到事件隊(duì)列里,更別說執(zhí)行了,這就導(dǎo)致出現(xiàn)了“丟幀”現(xiàn)象。而在圖中也可以注意到,func1執(zhí)行完畢,線程空閑了,func2就可以執(zhí)行了,這就使得func1和func2之間的執(zhí)行沒有時(shí)間間隔,這跟我們所預(yù)期的500ms產(chǎn)生一次結(jié)果是不同的。
而如果使用鏈?zhǔn)絪etTimeout調(diào)用,每次函數(shù)執(zhí)行的時(shí)候都會(huì)創(chuàng)建一個(gè)新的定時(shí)器。第二個(gè)setTimeout()調(diào)用使用了 arguments.callee 來獲取對(duì)當(dāng)前執(zhí)行的函數(shù)的引用,并為其設(shè)置另外一個(gè)定時(shí)器。這樣做的好處是,在前一個(gè)定時(shí)器代碼執(zhí)行完之前,不會(huì)向隊(duì)列插入新的定時(shí)器代碼,確保不會(huì)有任何缺失的間隔。而且,它可以保證在下一次定時(shí)器代碼執(zhí)行之前,至少要等待指定的間隔,避免了連續(xù)的運(yùn)行。代碼如下所示
setTimeout(function(){ //do something setTimeout(arguments.callee,interval); },interval)
用setTimeout方法的話,上面假設(shè)的場景就發(fā)生了改變,如下圖所示,在0s處觸發(fā)click事件,click事件執(zhí)行,在0.2s處觸發(fā)定時(shí)器,0.7s處第一個(gè)函數(shù)func1加入到事件隊(duì)列,click事件執(zhí)行了1s,在1s處func1執(zhí)行,2s處func1執(zhí)行結(jié)束,第二個(gè)setTimeout定時(shí)器才被觸發(fā),0.5s后將函數(shù)func2加入隊(duì)列,此時(shí)隊(duì)列為空,func2開始執(zhí)行,3.5s處func2執(zhí)行結(jié)束,又一個(gè)setTimeout定時(shí)器被觸發(fā),0.5s后將函數(shù)func3加入隊(duì)列,此時(shí)隊(duì)列為空,func3開始執(zhí)行。。。
通過上面這個(gè)場景,我們能知道當(dāng)需要用定時(shí)器來設(shè)置一個(gè)操作重復(fù)執(zhí)行,并且這個(gè)操作需要執(zhí)行一定的時(shí)間,記得用setTimeout,不用setInterval!
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
JavaScript對(duì)象學(xué)習(xí)小結(jié)
JavaScript 中的所有事物都是對(duì)象:字符串、數(shù)值、數(shù)組、函數(shù).幾乎用到的每個(gè)js都離不開它的js對(duì)象。此外,JavaScript 允許自定義對(duì)象,下面跟著小編學(xué)習(xí)javascript對(duì)象學(xué)習(xí)小結(jié),需要的朋友可以參考下2015-09-09JavaScript中逗號(hào)運(yùn)算符介紹及使用示例
這篇文章主要介紹了JavaScript中逗號(hào)運(yùn)算符介紹及使用示例,本文講解了逗號(hào)運(yùn)算符的定義、使用例子及實(shí)際使用的一些技巧,需要的朋友可以參考下2015-03-03從對(duì)象列表中獲取一個(gè)對(duì)象的方法,依據(jù)關(guān)鍵字和值
下面小編就為大家?guī)硪黄獜膶?duì)象列表中獲取一個(gè)對(duì)象的方法,依據(jù)關(guān)鍵字和值。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-09-09JavaScript常用數(shù)組去重的方法及對(duì)比詳解
數(shù)組去重在面試和工作中都是比較容易見到的問題。這篇文章主要是來測試多個(gè)方法,對(duì)下面這個(gè)數(shù)組的去重結(jié)果進(jìn)行分析討論,需要的可以參考一下2022-07-07Bootstrap modal 多彈窗之疊加關(guān)閉陰影遮罩問題的解決方法
這里也會(huì)遇到一次性關(guān)閉所有modal引起陰影遮罩的問題,也就是所有modal都關(guān)閉了,但是主頁面仍然被陰影遮罩。下面通過本文給大家分享解決方案,需要的朋友參考下吧2017-02-02javascript筆試題目附答案@20081025_jb51.net
網(wǎng)上找的javascript筆試題目,留檔給自己作參考。2008-10-10滾動(dòng)條變色 隱藏滾動(dòng)條與雙擊網(wǎng)頁自動(dòng)滾屏顯示代碼
滾動(dòng)條變色 隱藏滾動(dòng)條與雙擊網(wǎng)頁自動(dòng)滾屏顯示代碼2009-12-12js實(shí)現(xiàn)HTML中Select二級(jí)聯(lián)動(dòng)的實(shí)例
下面小編就為大家分享一篇js實(shí)現(xiàn)HTML中Select二級(jí)聯(lián)動(dòng)的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-01-01