大家都會的防抖與節流

這一篇文章我想寫一下防抖與節流,由於我本身不是很理解並且說實話,之前知道,可是老忘,雖然概念還有一些簡單的寫法會,但仍是缺少練習和深入的理解。app


當咱們不加防抖或節流的時候就像這樣,鼠標滑過觸發這麼屢次,因此咱們一個使用防抖或節流來限制它的請求次數而不是觸發次數。關於防抖與節流的應用和解釋自行查找資料。函數

<div id="app"></div>
function fn(e) {
    console.log(this);
    console.log(e);
    app.innerHTML = num ++;
}

1.防抖this

  • 簡單實現
function debounce(fn, delay) {
    let timer = null;
    return function(){
        clearTimeout(timer);
        timer = setTimeout(function () {
            fn();
        }, delay);
    }
}

使用節流後spa

app.onmousemove = fdebounce(fn, 1000);


咱們發現次數減小了太多,由於只要你在delay時間內不停地觸發就不會執行直到你的間隔時間大於delay纔會執行。3d

咱們來看一下this和event。

this是window,event是undefined。code

  • 修復this指向和事件參數
function debounce(fn, delay) {
    let timer = null,
        that;
    return function(e){
        that = this;
        clearTimeout(timer);
        timer = setTimeout(function () {  //this指向window(非嚴格模式)
            fn.apply(that, [e]);
        }, delay);
    }
}

或者是blog

function debounce(fn, delay) {
    let timer = null;
    return function(e){
        clearTimeout(timer);
        timer = setTimeout(()=>{ //箭頭函數
            fn.apply(this, [e]);
        }, delay);
    }
}

  • 加強版(是否當即執行)
function debounce(fn, delay, immediate) {
    let timer = null,
        that; 
    return function (e) {
        that = this;
        clearTimeout(timer);
        if(immediate){  //是否當即執行
            if(!timer){  // 若是沒有設置定時器就先執行
                fn.apply(that, [e]);
            }
            timer = setTimeout(function () { 
                timer = null;// 設置定時器,使其在delay毫秒內不能執行,過了delay毫秒後在執行
            }, delay);
        }else{ //不然延時執行
            timer = setTimeout(function () {
                fn.apply(that, [e])
            }, delay);
        }
    };
}
//這個if...else只能執行一個,要不先執行,要不延時執行


一開始會執行一次,由於錄製不能顯示鼠標因此理解一下。事件

  1. 節流
  • 簡易版(時間戳)
function throttle(fn, delay) {
    let last = 0, //上次執行時間
        now; //執行時的時間
    return function (e) {
        now = Date.now(); //當前時間
        if(now - last >= delay){  //若是兩次時間間隔大於delay,就執行
            last = now; //從新賦值
            fn(); 
        }
    };
}


在規定時間delay毫秒內總會執行一次事件。rem

  • setTimeout版本(修復this指向和事件參數)
function throttle(fn, delay) {
    let that,
        timer = null;
    return function (e) {
        that = this;
        if(!timer){  //若是沒設置定時器就執行
            timer = setTimeout(function () {
                fn.apply(that, [e]);
                timer = null; //果delay毫秒就設置timer,這樣就能delay執行一次
            }, delay);
        }
    };
}
  • 修復this指向和事件參數(時間戳)
function throttle(fn, delay) {
    let last = 0, //上次執行時間
        now; //執行時的時間
    return function (e) {
        now = Date.now(); //當前時間
        if(now - last >= delay){  //若是兩次時間間隔大於delay,就執行
            last = now; //從新賦值
            fn.apply(this, [e]); 
        }
    };
}
  • 區別it

    • 時間戳版本的會先執行
    • setTimeout版本的會後執行

因此能夠結合一下他們兩個。

  • 結合版
function throttle(fn, delay) {
    let last = 0,  //上次執行時間
        now, //當前時間
        leftTime, //剩餘時間
        that, 
        timer = null;
    return function (e) {
        that = this;
        now = Date.now();
        leftTime = delay - (now - last); 
        if(leftTime <= 0){ //保證一開始就執行(先執行)
            last = now;
            fn.apply(that, [e]);
        }else{
            timer = setTimeout(function() {  //延時執行
                fn.apply(that, [e]);
                timer = null;
            },delay)
        }
    };
}

這樣作整體思路沒錯,可是第一次會執行之後就是兩個一塊兒執行,由於條件都知足。

  • 修改
function throttle(fn, delay) {
    let last = 0,
        now,
        leftTime,
        that,
        timer = null;
    return function (e) {
        that = this;
        now = Date.now();
        leftTime = delay - (now - last);
        if(leftTime <= 0){
            if(timer){ //若是有定時器就清除
                clearTimeout(timer);
                timer = null;
            }
            last = now;
            fn.apply(that, [e]);
        }else if(!timer){
            timer = setTimeout(function() {
                last = now; //若是時間知足就讓他不知足
                //總之除了第一次就只讓其中一個執行
                fn.apply(that, [e]);
                timer = null;
            },delay)
        }
    };
}

一開始執行一次(時間戳),最後中止在執行一次(setTimeOut)。

相關文章
相關標籤/搜索