1. 程式人生 > 其它 >效能優化方案

效能優化方案

1.節流

從滾動條監聽的例子說起:

監聽瀏覽器滾動事件,返回當前滾條與頂部的距離

```

function showTop() {

var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;

console.log("滾動條位置: " + scrollTop);

}

window.onscroll = showTop;

```

在執行的時候會發現存在一個問題:這個函式的預設執行頻率,太!高!了!。 高到什麼程度呢?以chrome為例,我們可以點選選中一個頁面的滾動條,然後點選一次鍵盤的【向下方向鍵】,會發現函式執行了

8-9次!

然而實際上我們並不需要如此高頻的反饋,畢竟瀏覽器的效能是有限的,不應該浪費在這裡,所以接著討論如何優化這種場景。

防抖(debounce)

在第一次觸發事件時,不立即執行函式,而是給出一個期限值,比如200ms,然後,

如果在200ms內沒有再次觸發滾動事件,那麼就執行函式

如果200ms內再次觸發滾動事件,那麼當前的計時取消,重現開始計時

效果:實現如果短時間內觸發統一事件,那麼只會執行一次函式

實現:既然前面都提到了計時,那實現的關鍵就在於setTimeout這個函式,由於還需要一個變數來儲存計時,考慮維護全域性純淨,可以藉助閉包來實現:

```

/**

* fn: function

需要防抖的函式

* delaynumber 防抖期限值

*/

function debounce(fn, delay) {

let timer = null; // 藉助閉包

return function () {

if(timer) {

clearTimeout(time);

}

timer = setTimeout(fn, delay);

}

}

window.onscroll = debounce(showTop, 1000);

```

window.onscroll = debounce(showTop, 1000);

此時會發現,必須在停止滾動1秒以後,才會打印出滾動條位置。

到這裡,已經把防抖實現了,現在給出定義:

對於短時間內連續觸發的事件(上面的滾動事件),

防抖的含義就是讓某個時間期限(如上面的1000毫秒)內,事件處理函式只執行一次。

2.節流(throttle)

繼續思考,使用上面的防抖方案來處理問題的結果是:

如果在限定時間段內,不斷觸發滾動事件(比如某個使用者閒著無聊,按住滾動不斷的拖來拖去),只要不停止觸發,理論上就永遠不會輸出當前距離頂部的距離。

但是如果產品同學的期望處理方案是:即使使用者不斷拖動滾動條,也能在某個時間間隔之後給出反饋呢?

我們可以設計一種類似控制閥門一樣定期開放的函式,也就是讓函式執行一次後,在某個時間段內暫時失效,過了這段時間後再重新啟用

效果:如果短時間內大量觸發同一事件,那麼在函式執行一次之後,該函式在指定的時間期限內不再工作,直至過了這段時間才重新生效。

實現 這裡藉助setTimeout來做一個簡單

```/**

* fn: function 需要節流的函式

* delaynumber 節流期限值

*/

function throttle(fn, delay) {

let valid = true;

return function () {

if(!valid) {

return false; //時間未到,暫不執行

}

valid = false;

//請注意,節流函式並不止上面這種實現方案,例如可以完全不借助setTimeout

// 可以把狀態位換成時間戳,然後利用時間戳差值是否大於指定間隔時間來做判定。

// 也可以直接將setTimeout的返回的標記當做判斷條件-判斷當前定時器是否存在

// 如果存在表示還在冷卻,並且在執行fn之後消除定時器表示啟用,原理都一樣

setTimeout(() => {

fn();

valid = true;

}, delay);

}

}

```

window.onscroll = throttle(showTop, 200);

執行以上程式碼的結果是:

如果一直拖著滾動條進行滾動,那麼會以1s的時間間隔,持續輸出當前位置和頂部的距離,大大提升網頁遊戲執行速度