1. 程式人生 > >防抖函數與節流函數

防抖函數與節流函數

實現 多次 timer undefined clear 保存 clas 圖片 method

應用場景

我們經常需要監聽滾動條滾動或者鼠標的移動,但是瀏覽器觸發這類事件的頻率非常高,可能10幾毫秒就觸發一次,有的時候我們只需要處理函數執行一次,比如文本輸入驗證,執行多次處理函數反而沒必要。

常規實現,以監聽 scroll 事件為例

window.onscroll  = function () {
//滾動條位置
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
  console.log(‘滾動條位置:‘ + scrollTop);
}

解決方法:

減少DOM操作的頻度,也就是稀疏處理函數的執行頻率,解決方法就是函數防抖以及函數分流。函數防抖表示只執行一次處理函數,函數分流指降低處理函數的執行頻率。

函數防抖

指多次觸發事件後,事件處理函數只執行一次,而且是在事件操作停止的時候。具體思路就是延遲處理函數,如果設定的時間到來之前又一次觸發了事件,就清除上一次的定時器,重新定時。

簡單實現的例子:

window.onscroll=function(){
    if(timer){
        clearTimeout(timer);
    }
    timer=setTimeout(function(){
        let 
scrollTop=document.body.scrollTop||document.documentElement.scrollTop;
        console.log(
滾動位置:+scrollTop); timer=undefined; },200); }

這裏有一個保存timer的技巧,如果不保存timer,那麽執行完事件處理函數,timer將被銷毀,我們也就無法再清除定時器了,所以要保存這個變量,即使他所在的函數作用域對應的函數已經執行完了。

防抖函數的封裝使用 閉包

//封裝方法之閉包
//閉包:如果想讓一個函數執行完,函數內的某個變量(timer)仍然保留。就可以用閉包

function debounce(method,delay){
    var timer=null;
    return
function(){ var that=this; var args=arguments; clearTimeout(timer); timer=setTimeout(function(){ method.apply(that,args); },delay); } } window.onscroll=debounce(function(){ var scrollTop=document.body.scrollTop||document.documentElement.scrollTop; console.log(scrollTop); },200);

適用性:監聽滾動條的位置,控制是否顯示返回頂部按鈕是,就可以將抖動函數應用其中。

不適用:做圖片懶加載時,需要通過滾動位置實時顯示圖片時,如果使用防抖函數,懶加載函數就會不斷被延遲,只有停下來的時候才會被執行,防抖函數對於這種需要實時觸發事件的情況就顯得不是很友好了。

節流函數

觸發事件函數後,短時間內無法連續調用,只有上一次函數執行後,過了規定的時間間隔,才能進行下一次的函數調用。

原理:對處理函數進行延時操作,若設定的延時到來之前,再次觸發事件,則清除上一次的延時操作定時器,重新定時。

簡單實現的例子:

var startTime=Date.now();//開始時間
var time=500;//間隔時間
var timer;
window.onscroll=function throttle(){
    var currentTime=Date.now();
    if(currentTime-startTime>=time){
         var scrollTop=document.body.scrollTop||document.documentElement.scrollTop;
         console.log(滾動位置:+scrollTop);
         startTime=currentTime;
    }
    else{
         clearTimeout(timer);
         timer=setTimeout(function(){
            throttle();
         },50);
    }
}    

節流函數的封裝使用 閉包

/**
 * 函數節流throttle
 * @param method事件觸發的操作
 * @param delay延遲執行函數的時間
 * @param mustRunDelay超過多長時間必須執行一次函數
 */
function throttle(method,delay,mustRunDelay){
    var timer=null;//計時器
    var args=arguments;
    var startTime=0;//開始時間
    var currentTime=0;//當前時間

    return function(){
        var that=this;
        currentTime=Date.now();
        if(!startTime){
            startTime=currentTime;
        }
        if(currentTime-startTime>=mustRunDelay){
            method.apply(that,args);
            startTime=currentTime;
        }
        else{
            clearTimeout(timer);
            timer=setTimeout(function(){
                method.apply(that,args)
            },delay);
        }
    }
}
window.onscroll=throttle(function(){
    var scrollTop=document.body.scrollTop||document.documentElement.scrollTop;
    console.log(scrollTop);
},50,500);

函數防抖與函數分流的思想都是通過設置定時器控制函數的執行頻率。

防抖函數與節流函數