防抖與節(jié)流

防抖或是節(jié)流,都是為了限制函數(shù)執(zhí)行的次數(shù)。

防抖:通過setTimeout,在一定時間間隔內,將多次觸發(fā)變?yōu)橐淮斡|發(fā)。
節(jié)流:減少一段時間內的觸發(fā)次數(shù)。(控制流量)

防抖:

// 模擬表單提交
const btn = document.getElementById('btn');
btn.addEventListener('click', debounce(submit, 1000));
一、最基礎版本,實現(xiàn)1秒內只提交一次:

思路:

  • addEventListener的第二個參數(shù)為一個函數(shù),而不是直接函數(shù)調用,所以debounce要返回一個函數(shù)
  • 最外面聲明timer,有timer則清除,重新計時1s后submit。這樣總是最后一次觸發(fā)1s后才會submit。
function debounce(fn, delay){
    var timer = null;

    return function(){
        if(timer){ clearTimeout(timer); }

        timer = setTimeout(() => {
            fn();
        }, delay);
    }
}

function submit(){
    console.log('submit');
}

這樣存其實依然存在問題,如何在提交函數(shù)(submit)中拿到正確的事件參數(shù)e,以及this(this應該是指向btn)?
e是通過addEventListener第二個參數(shù)回調函數(shù)傳遞的,也就是在debounce函數(shù)return的匿名函數(shù)中,可以拿到e,直接傳給fn(timer的回調是箭頭函數(shù),所以可以直接拿到外部綁定的this和arguments)。
為了兼容除e之外的未知參數(shù),使用arguments形式傳遞參數(shù)。
apply直接傳遞數(shù)組形式arguments并改變fn中的this指向為箭頭函數(shù)綁定的this,也就是指向btn。

function debounce(fn, delay){
    var timer = null;

    return function(){
        console.log(e);  // PointerEvent
        if(timer){ clearTimeout(timer); }

        timer = setTimeout(() => {
            console.log(this, arguments);  // btn  Arguments: []
            fn.apply(this, arguments);
        }, delay);
    }
}

function submit(){
    console.log('this:', this);  // btn
    console.log('e:', arguments[0]); // 輸出PointerEvent
}
二、基本的防抖已實現(xiàn),但還有一個小問題:每次的submit執(zhí)行總會延遲1s,這樣適用于類似監(jiān)聽搜索框變化,發(fā)起搜索的場景,而對于類似表單提交場景是不需要延遲的,這樣用戶體驗是不友好的,如何能在第一次點擊時可以立即執(zhí)行?(換句話說,只在連續(xù)點擊的第一次點擊時立即執(zhí)行,后面的點擊無響應)
function debounce(fn, delay){
    var timer = null;

    return function(){
        const firstClick = !timer; // firstClick標記是否第一次點擊,通過timer來判斷

        if(timer){ clearTimeout(timer); }

        if(firstClick){
            fn.apply(this, arguments);  // 如果是第一次,立即執(zhí)行
        }
        timer = setTimeout(() => {
            timer = null;  // 1s后timer置為初始值null(不能clearTimeout,這樣timer依然存在,值為number編號)
        }, delay);
    }
}

節(jié)流

最外層初始化begin為0,第一次點擊的時間戳和begin比較必然大于delay,后面每次點擊,判斷距離上次執(zhí)行submit事件大于2s才再次執(zhí)行,并更新begin

const btn = document.getElementById('btn');
btn.addEventListener('click', throttle(submit, 2000));

function throttle(fn, delay){
    var begin = 0;

    return function(){
        var cur = new Date().getTime();
        if(cur - begin > delay){
            console.log(cur - begin); 
            submit();
            begin = cur;
        }
    }
}

function submit(){
    console.log('submit');
}

// 連續(xù)多次點擊,log輸出:
1635479979895
submit
13143
submit
2073
submit
2002
submit
2019
submit
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容