在監聽窗口進行 resize、scroll 等調用函數頻率很高的操作時,如果每次都做相應的處理,則會加重瀏覽器的負擔,導致渲染延遲,甚至是假死,這樣會給用戶帶來非常糟糕的體驗。爲此我們必須在特定場景下限制調用頻率,但是又不影響效果。
一、防抖
防抖技術
:使得事件被觸發 N 秒之後再執行回調,如果再 N 秒內再次觸發,則重新倒計時。
var btn = document.getElementById('btn');
var submit = function(value) {
console.log(arguments[0]);
}
//監聽按鈕的點擊事件
btn.addEventListener('click', debounce(submit, 'hello'));
function debounce(fn, value) {
var timer = null;
return function() {
//如果timer還存在,則清空timer,並重新計時
if(timer) {
clearTimeout(timer);
}
timer = setTimeout(function(){
fn.call(this, value);
}, 3000);
}
}
結果如下:
多次觸發按鈕的點擊事件,但是這些都在3S之內觸發的,所以每一次點擊都會清空當前的計時器,然後重新生成新的計時器。所以等到最後一次超過 3S 纔會回調 Submit。
防抖技術函數只會在頻繁調用時只執行一次。比如用戶在提交表單時,防止多次提交表單。或者搜索聯想詞功能類似時,在用戶連續輸入完成之後再向服務器發送。
二、節流
節流技術
:當某一事件連續被觸發時,保證一定時間內只做一次處理。
var btn = document.getElementById('btn');
var submit = function (value) {
console.log(value);
}
function throttle(fn, value) {
var flag = true;
return function() {
//如果本次定時器還沒執行,則直接返回
if(!flag) {
return ;
}
flag = false;
setTimeout(function(){
fn.call(this, value);
flag = true;
}, 1000);
}
}
btn.addEventListener('click',throttle(submit, "hellos"));
結果如下:
多次點擊按鈕,但是回調函數只會以1S每次的頻率進行執行。本次回調執行完成之後會將flag置爲true,這樣就可以生成下一次執行回調的定時器。
- 拖拽場景:固定時間內只執行一次,防止超高頻次觸發位置變動
- 縮放場景:監控瀏覽器 resize
- 動畫場景:避免短時間內多次觸發動畫引起性能問題
三、總結
防抖和節流的區別在於連續觸發時執行的次數。如果只想在最後執行一次的場景,需要用防抖技術。如果想在期間以固定頻率觸發,則使用節流。