首頁  >  文章  >  web前端  >  聊聊盡量別用setInterval的原因

聊聊盡量別用setInterval的原因

青灯夜游
青灯夜游轉載
2021-01-08 18:37:554855瀏覽

聊聊盡量別用setInterval的原因

為什麼盡量別用setInterval?以下這篇文章就來淺談一下盡量別用setInterval的原因。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有幫助。

在開發一個線上聊天工具時,常常會有過多少毫秒就重複執行一次某操作的需求。 “沒問題”,大家都說,“用setInterval好了。”我覺得這個點子很糟糕。

原因之一:setInterval無視程式碼錯誤

setInterval有個討厭的習慣,就是對自己呼叫的程式碼是否報錯這件事漠不關心。換句話說,如果setInterval執行的程式碼因為某種原因出了錯,它還會持續不斷(不管不顧)地呼叫該程式碼。看程式碼

function a() {
    try{
        a.error.here;
    } catch(e){
        $(&#39;body&#39;).append(&#39;<div>&#39; + e.toString() + &#39;</div>&#39;);
        throw e;
    }
}
function b() {
    try{
        b.error.here;
    } catch(e)
    {
        $(&#39;body&#39;).append(&#39;<div>&#39; + e.toString() + &#39;</div>&#39;);
        throw e;
    }
    setTimeout(b, 2000);
}
setInterval(a, 2000);
setTimeout(b, 2000);

原因之二:setInterval無視網路延遲

假設你每隔一段時間就透過Ajax輪詢一次伺服器,看看有沒有新數據(注意:如果你真的這麼做了,那恐怕你做錯了;建議使用「補償性輪詢」(backoff polling)[1])。而由於某些原因(伺服器過載、臨時斷網、流量劇增、用戶頻寬受限,等等),你的請求要花的時間遠比你想像的要長。但setInterval不在乎。它仍然會按定時持續不斷地觸發請求,最終你的客戶端網路佇列會塞滿Ajax呼叫。看程式碼

var n = 0,
    t = 0,
    u = 0,
    i, s = &#39;Stopping after 25 requests, to avoid killing jsfiddle’s server&#39;;
function a() {
    $.post(&#39;/ajax_html_echo/&#39;, function () {
        --n;
    });
    ++n;
    ++t;
    $(&#39;#reqs&#39;).html(n + &#39; a() requests in progress!&#39;);
    if (t > 25) {
        clearInterval(i);
        $(&#39;#reqs&#39;).html(s);
    }
}
function b() {
    ++u;
    $.post(&#39;/ajax_html_echo/&#39;, function () {
        $(&#39;#req2&#39;).html(&#39;b(): &#39; + new Date().toString());
        if (u <= 25) {
            setTimeout(b, 500);
        } else {
            $(&#39;#req2&#39;).html(s);
        }
    });
}
i = setInterval(a, 500);
setTimeout(b, 500);

原因之三:setInterval不保證執行

與setTimeout不同,你並不能保證到了時間間隔,程式碼就準能執行。如果你呼叫的函數需要花很長時間才能完成,那麼某些呼叫會被直接忽略。看程式碼

function slow() {
    $.ajax({
        url: &#39;/echo/html/&#39;,
        async: false,
        data: {
            delay: 1
        },
        complete: function () {
        }
    });
    $(&#39;#reqs&#39;).text(~~((new Date() - start) / 100) + &#39; expected, &#39; + iters + &#39; actual&#39;);
    if (iters++ > 4) {
        $(&#39;#reqs&#39;).append(&#39;<br>Stopping after 5 iterations&#39;);
        clearInterval(iv);
    }
};
var iv = setInterval(slow, 100), start = +new Date(), iters = 0;

解決之道很簡單:用setTimeout

與其使用setInterval,不如在適當的時刻透過setTimeout來呼叫函數自身。在前面兩個範例中,使用setInterval的函數a都出錯了,而使用setTimeout的函數b則表現很好。

如果必須保證間隔相等怎麼辦?

如果確實要保證事件「勻速」被觸發,那可以用希望的延遲減去上次呼叫所花時間,然後將得到的差值作為延遲動態指定給setTimeout 。不過,要注意的是JavaScript的計時器並不是非常精確[2]。因此你不可能得到絕對「平均」的延遲,即使使用setInterval也不行,原因很多(例如垃圾回收、JavaScript是單執行緒的,等等)。此外,目前瀏覽器也會將最小的逾時時間固定在4ms到15ms之間。因此不要指望一點誤差也沒有。

更多程式相關知識,請造訪:程式設計教學! !

以上是聊聊盡量別用setInterval的原因的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:cnblogs.com。如有侵權,請聯絡admin@php.cn刪除