JS高級定時器

高級定時器

關(guān)于定時器要記住的最重要的事情是:指定的時間間隔表示何時將定時器的代碼添加到隊列,而不是何時實際執(zhí)行代碼车摄。

定時器對隊列的工作方式是,當(dāng)特定時間過去后將代碼插入。注意没宾,給隊列添加代碼并不意味著對它立刻執(zhí)行忍法,而只能表示它會盡快執(zhí)行。設(shè)定一個 150ms 后執(zhí)行的定時器不代表到了 150ms代碼就立刻執(zhí)行榕吼,它表示代碼會在 150ms 后被加入到隊列中饿序。如果在這個時間點(diǎn)上,隊列中沒有其他東西羹蚣,那么這段代碼就會被執(zhí)行原探,表面上看上去好像代碼就在精確指定的時間點(diǎn)上執(zhí)行了。其他情況下顽素,代碼可能明顯地等待更長時間才執(zhí)行咽弦。

定時器僅僅只是計劃代碼在未來的某個時間執(zhí)行。執(zhí)行的時間是不能保證的胁出,因為在頁面的生命周期中型型,不同時間可能有其他代碼在控制 JavaScript 進(jìn)程。在頁面下載完后的代碼運(yùn)行全蝶、事件處理程序闹蒜、Ajax 回調(diào)函數(shù)都必須使用同樣的線程來執(zhí)行。實際上抑淫,瀏覽器負(fù)責(zé)進(jìn)行排序绷落,指派某段代碼在某個時間點(diǎn)運(yùn)行的優(yōu)先級。

可以把 JavaScript 想象成在時間線上運(yùn)行的始苇。當(dāng)頁面載入時砌烁,首先執(zhí)行是任何包含在 < script> 元素中的代碼,通常是頁面生命周期后面要用到的一些簡單的函數(shù)和變量的聲明催式,不過有時候也包含一些初始數(shù)據(jù)的處理函喉。在這之后,JavaScript 進(jìn)程將等待更多代碼執(zhí)行荣月。當(dāng)進(jìn)程空閑的時候管呵,下一個代碼會被觸發(fā)并立刻執(zhí)行。例如喉童,當(dāng)點(diǎn)擊某個按鈕時撇寞, onclick 事件處理程序會立刻執(zhí)行,只要 JavaScript 進(jìn)程處于空閑狀態(tài)堂氯。這樣一個頁面的時間線類似于下圖(引自高程三)

下面是有循環(huán)的代碼

<div id="test">2222222222</div>
<script>
    var oTest=document.getElementById("test");
    oTest.onclick=function(){
        var nowTime=new Date();
        setTimeout(function(){
            console.log("定時器的代碼");
            console.log(new Date()-nowTime);//534
        },100);
        for(var i=0;i<1000000000;i++){}
        var clickTime=new Date();
        console.log(clickTime-nowTime);//532
    }
</script>

點(diǎn)擊后蔑担,會發(fā)現(xiàn),并不是過100毫秒執(zhí)行的咽白;如果去掉for循環(huán)啤握,那是差不多的;

重復(fù)定時器 setInterval

使用 setInterval() 創(chuàng)建的定時器確保了定時器代碼規(guī)則地插入隊列中晶框。這個方式的問題在于排抬,定時器代碼可能在代碼再次被添加到隊列之前還沒有完成執(zhí)行懂从,結(jié)果導(dǎo)致定時器代碼連續(xù)運(yùn)行好幾次,而之間沒有任何停頓蹲蒲。

幸好番甩,JavaScript 引擎夠聰明,能避免這個問題届搁。

當(dāng)使用setInterval() 時缘薛,

  • 1、僅當(dāng)沒有該定時器的任何其他代碼實例時卡睦,才將定時器代碼添加到隊列中宴胧。

這確保了定時器代碼加入到隊列中的最小時間間隔為指定間隔。

但是由此引發(fā)了setInterval 定時器規(guī)則有兩個問題:

  • 1表锻、某些間隔會被跳過恕齐;
  • 2、多個定時器的代碼執(zhí)行之間的間隔可能會比預(yù)期的兴惭贰显歧;

因為規(guī)則是:僅當(dāng)沒有該定時器的任何其他代碼實例時,才將定時器代碼添加到隊列中码耐。

如果設(shè)置一個重復(fù)定時器 (setInterval)追迟; 處理的時間為300毫秒;但是間隔時間是200毫秒骚腥;間隔時間小于單次定時器內(nèi)代碼的處理時間;就會同時出現(xiàn)跳過間隔且連續(xù)運(yùn)行定時器代碼的情況瓶逃。(隊列中已經(jīng)有一次相同的定時器時束铭,第二次添加會被忽略

高程三的例子:

假設(shè),某個 onclick 事件處理程序使用 setInterval() 設(shè)置了一個 200ms 間隔的重復(fù)定時器厢绝。如果事件處理程序花了 300ms多一點(diǎn)的時間完成契沫,同時定時器代碼也花了差不多的時間,就會同時出現(xiàn)跳過間隔且連續(xù)運(yùn)行定時器代碼的情況咸作。

這個例子中的第 1 個定時器是在 205ms 處添加到隊列中的陨晶,但是直到過了 300ms 處才能夠執(zhí)行辞友。當(dāng)執(zhí)行這個定時器代碼時,在 405ms處又給隊列添加了另外一個副本会通。在下一個間隔,即 605ms 處娄周,第一個定時器代碼仍在運(yùn)行涕侈,同時在隊列中已經(jīng)有了一個定時器代碼的實例。所以在這個時間點(diǎn)上的定時器代碼不會被添加到隊列中煤辨。

結(jié)果在 5ms處添加的定時器代碼結(jié)束之后裳涛,405ms 處添加的定時器代碼就立刻執(zhí)行木张。

解決的辦法

使用鏈?zhǔn)?setTimeout() 調(diào)用

setTimeout(function(){
    //處理中
    setTimeout(arguments.callee, 400);
}, 500);
  • 在前一個定時器代碼執(zhí)行完之前,不會向隊列插入新的定時器代碼端三,確保不會有任何缺失的間隔舷礼。

  • 而且,它可以保證在下一次定時器代碼執(zhí)行之前郊闯,至少要等待指定的間隔妻献,避免了連續(xù)的運(yùn)行。這個模式主要用于重復(fù)定時器虚婿,

    <!doctype html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>Document</title>
    <link rel="stylesheet" href="test.css"/>
    <style>
    #test{
    width: 200px;height: 200px;background-color: #002d32;
    position: absolute;
    top: 300px;
    left: 20px;
    }
    </style>
    </head>
    <body>
    <div id="test">2222222222</div>
    <script>
    var div = document.getElementById("test");
    var left;
    var timer=setTimeout(function(){
    //處理中
    left = parseFloat(window.getComputedStyle(div,null).left)+5;
    console.log(left);
    div.style.left = left + "px";
    if (left < 200) {
    setTimeout(arguments.callee, 500);
    console.log("star agin ");
    }else{
    console.log("clear Timeout");
    clearTimeout(timer);
    }
    }, 10);
    </script>
    </body>
    </html>

JavaScript 動畫中使用這個模式很常見旋奢。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市然痊,隨后出現(xiàn)的幾起案子至朗,更是在濱河造成了極大的恐慌,老刑警劉巖剧浸,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锹引,死亡現(xiàn)場離奇詭異,居然都是意外死亡唆香,警方通過查閱死者的電腦和手機(jī)嫌变,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來躬它,“玉大人腾啥,你說我怎么就攤上這事》胂牛” “怎么了倘待?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長组贺。 經(jīng)常有香客問我凸舵,道長,這世上最難降的妖魔是什么失尖? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任啊奄,我火速辦了婚禮,結(jié)果婚禮上掀潮,老公的妹妹穿的比我還像新娘菇夸。我一直安慰自己,他們只是感情好胧辽,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布峻仇。 她就那樣靜靜地躺著,像睡著了一般邑商。 火紅的嫁衣襯著肌膚如雪摄咆。 梳的紋絲不亂的頭發(fā)上凡蚜,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天,我揣著相機(jī)與錄音吭从,去河邊找鬼朝蜘。 笑死,一個胖子當(dāng)著我的面吹牛涩金,可吹牛的內(nèi)容都是我干的谱醇。 我是一名探鬼主播,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼步做,長吁一口氣:“原來是場噩夢啊……” “哼副渴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起全度,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤煮剧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后将鸵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體勉盅,經(jīng)...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年顶掉,在試婚紗的時候發(fā)現(xiàn)自己被綠了草娜。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,861評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡痒筒,死狀恐怖宰闰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情簿透,我是刑警寧澤议蟆,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站萎战,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏舆逃。R本人自食惡果不足惜蚂维,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望路狮。 院中可真熱鬧虫啥,春花似錦、人聲如沸奄妨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽砸抛。三九已至评雌,卻和暖如春树枫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背景东。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工砂轻, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人斤吐。 一個月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓搔涝,卻偏偏與公主長得像,于是被迫代替她去往敵國和親和措。 傳聞我的和親對象是個殘疾皇子庄呈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評論 2 361

推薦閱讀更多精彩內(nèi)容