沒用系列之定時器

最近有個亂七八糟的產品,又加了個亂七八糟的需求,結果還被懟了亂七八糟,阿西吧!css

在頁面設置兩個定時器,一個倒計時,另外一個輪詢,有衝突(臆想)。數組

基礎 setTimeout

最基礎的定時器是 setTimeout,指定 xx ms 後執行。性能優化

來看它的一個缺陷:性能

for () {
    // 運行了 1s
}

// 指定 100ms 後執行
setTimeout('console.log(1)', 100);
複製代碼

打印日誌的時間在 1s 後,而不是咱們預期的 100ms。優化

衆所周知 js 是單線程的,在線程被佔用的狀況下,沒法進行另外一個操做,只能加入到執行隊列中,而一旦線程空閒時,會當即執行隊列中的操做。ui

所以,setTimeout 的執行時間是不太精確的。spa

重複 setInterval

setInterval 主要用來重複執行,指定 xx ms 間隔。線程

它是在各個時間點加入到執行隊列中,等進程空閒後執行。可能出現某個間隔被跳過的狀況:日誌

setInterval(function longTime() {
    for () {
        // 運行了 300ms
    }
}, 100);
複製代碼

longTime 運行期間,其它 longTime 副本也被加入到隊列中,多個只執行最早加入的那個,其它將被跳過。code

這個小缺陷能夠用高級點的技巧避免:

setTimeout(function foo() {
    // 一些操做

    // 遞歸,作到相似 setInterval 的效果
    // 且比 setInterval 更可靠,保證了間隔不被跳過
    setTimeout(foo, 100);
}, 100);
複製代碼

應用

定時器的延遲執行功能,可應用到許多場景,例如倒計時等等。更多的是性能優化這一塊。

數組分塊 Yielding Processes

假設有這樣的場景:

const arr = new Array(1000);

for (let i = 0; i < arr.length; i++) {
    // 操做數組的每一項,同步的
    // 運行了 100ms
}

// 總共耗時 1000x0.1 = 100s
複製代碼

上面的場景,界面在 100s 內都無響應,由於 js 線程一直被佔用,沒法執行其它操做。

使用定時器把數組分紅一塊一塊處理:

const arr = new Array(1000);
const chunkSize = 1; // 分塊大小

setTimeout(function foo() {
    const arrChunk = arr.splice(0, chunkSize);

    // 操做分塊後的數組 arrChunk
    // 運行了 100ms * chunkSize

    if (arr.length > 0) {
        // 100ms 的緩衝期,讓界面不至於失去響應
        setTimeout(foo, 100);
    }
}, 100);
複製代碼

節流和防抖 throttle & debounce

節流和防抖兩個概念太類似了,每次都會把它倆搞混。。。都是減小觸發頻率,提升性能,最主要的差異應該是觸發時間。

  • 節流觸發時間在前。相似 setInterval 的執行機制,觸發屢次時,在指定的時間間隔內,只有第一次的纔會執行,其它的跳過(手動)。
  • 防抖觸發時間在後。與 setTimeout 相似,延遲執行,觸發屢次時,只執行最後一個,其它的被清除(手動)。

應用場景上也能混用,,,大概瞭解下就好了

// 大多用在 scroll 上的節流
// 也可使用 px 單位,好比 10px
HTMLElement.addEventListener('scroll', function throttle() {
    const ts = Date.now();

    // 上次調用時間過了 100ms
    if (ts - lastInvokeTs > 100) {
        lasInvokeTs = ts;

        // 一些操做
    }
});

// 大多用在 keyup、resize 上的防抖
HTMLElement.addEventListener('keyup', function debounce() {
    // 延遲到觸發時 100ms 後
    clearTimeout(timer);
    timer = setTimeout(function () {
        // 一些操做
    }, 100);
});
複製代碼

針對 Css 渲染方面的節流能夠考慮原生更流暢的 API requestAnimationFrame

HTMLElement.addEventListener('scroll', function foo() {
    if (!changing) {
        requestAnimationFrame(function () {
            // 一些操做

            changing = false;
        });
    }

    changing = true;
});
複製代碼

css-tricks 上更好的一篇解釋防抖節流的文章

The End

通常來講頁面裏同時設置幾個定時器問題不大,js 的執行速度很快,偏差也大不到哪去,何況 ms 級別的偏差也感受不到。

節流和防抖仍是比較混,阿西吧!

相關文章
相關標籤/搜索