節流函數和防抖函數學習

首先自己理解的概念:

防抖函數:防抖按照我的理解就是不管你觸發多少次,都等到你最後觸發後過一段你指定的時間才觸發

節流函數:節流就是,不管怎麼觸發,都是按照指定的間隔來執行。

實例:

防抖函數例子:

基礎版本:


現在有個要求就是剛開始的時候也觸發,最後一次也觸發,並且可以配置,先寫個測試頁面方便測試功能,每次按空格鍵就會讓數字加1,來測試防抖和節流函數。


通過 leading 和 trailing 兩個參數來決定開始和結束是否執行,如果 leading 爲 true,則沒次按空格都會執行一次,如果 trailing 爲 true,則每次結束都會將最後一次觸發執行。以防抖函數距離,如果兩者都爲 true,則第一次按空格會加 1,然後快速按空格,此時裏面的 getUserAction 並不會執行,而是等到鬆手後再執行,加入 trailing 爲 false,則鬆手後不會執行。


解釋一下,每次記錄上次調用的時間,與現在的時間對比,小於間隔的話,第一次執行後之後就不會執行,大於間隔或在間隔時間後調用了,則重置 flag,可以與上面那個基本版的對比着看。

函數防抖的應用場景,最常見的就是用戶註冊時候的手機號碼驗證和郵箱驗證了。只有等用戶輸入完畢後,前端才需要檢查格式是否正確,如果不正確,再彈出提示語。以下還是以頁面元素滾動監聽的例子,來進行解析:

// 函數防抖
var timer = false;
document.getElementById("debounce").onscroll = function(){
    clearTimeout(timer); // 清除未執行的代碼,重置回初始化狀態

    timer = setTimeout(function(){
        console.log("函數防抖");
    }, 300);
};  

 函數防抖的要點,也是需要一個setTimeout來輔助實現。延遲執行需要跑的代碼。
 如果方法多次觸發,則把上次記錄的延遲執行代碼用clearTimeout清掉,重新開始。
 如果計時完畢,沒有方法進來訪問觸發,則執行代碼。

 這個方法的作用是監聽ID爲debounce元素的滾動事件
 進入滾動事件方法體的時候,做的第一件事就是清除上次未執行的setTimeout。而setTimeout的引用id由變量timer記錄。
clearTimeout方法,允許傳入無效的值。所以這裏直接執行clearTimeout即可。
 然後,將需要執行的代碼放入setTimeout中,再返回setTimeout引用給timer緩存。
 如果倒計時300ms以後,還沒有新的方法觸發滾動事件,則執行setTimeout中的代碼。

 函數防抖的實現重點,就是巧用setTimeout做緩存池,而且可以輕易地清除待執行的代碼。
 其實,用隊列的方式也可以做到這種效果。這裏就不深入了。

函數防抖:註冊時郵箱的輸入框,隨着用戶的輸入,實時判斷郵箱格式是否正確。此時,每一次的用戶輸入都觸發郵箱格式檢測事件,造成了浪費,於是設置兩次輸入之間的時間間隔大於800ms時(用戶結束輸入時),再執行檢查郵箱格式。

[javascript] view plain copy
  1. const filter  = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;  
  2. $("#email").on("keyup",checkEmail());  
  3. function checkEmail(){  
  4.     let timer=null;  
  5.     return function (){  
  6.         clearTimeout(timer);  
  7.         timer=setTimeout(function(){  
  8.             console.log('執行檢查');  
  9.         },800);  
  10.     }  
  11. }  
當第一次輸入事件觸發,設置定時:在800ms之後執行檢查。
假如只過了100ms,上次的定時還沒執行,此時清除定時,重新定時800ms。
緊跟着又來了一次輸入,上次定時依然沒執行,再次清除定時,重新定時800ms。
...
直到最近一次的輸入,後面沒有緊鄰的輸入了,這最近一次的輸入定時計時結束,終於執行了檢查代碼。
結果是:如果兩次輸入觸發事件的時間間隔不足800ms的,不執行檢查代碼。 兩次觸發事件的時間間隔大於800ms了,則前面的執行檢查。
這就是傳說中的 函數防抖

節流

節流就是,不管怎麼觸發,都是按照指定的間隔來執行,同樣給個基本版。

同樣和防抖函數一樣加上兩個參數,也可使用上面的例子來測試,其實兩者的代碼很類似。


函數節流:一個加載新聞的列表頁,只要滾動到頁面的最下面就繼續加載一部分新聞出來,即滾動加載。這時,就要監聽滾動事件,判斷若滾動
到頁面底部了,就執行加載新聞的代碼。
[javascript] view plain copy
  1. $(window).scroll(loadMore());  
  2.     function loadMore(){  
  3.         var canRun=true;  
  4.         return function(){  
  5.             if(!canRun){return;}  
  6.             canRun=false;  
  7.             setTimeout(function(){  
  8.                 console.log("執行滾動事件");  
  9.                 var docHeight=$(document).height();  
  10.                 var winHeight=$(window).innerHeight();  
  11.                 var scrollDistance=$(window).scrollTop();  
  12.                 if( docHeight - (winHeight+scrollDistance) <=100 ){  
  13.                     console.log('加載中...');  
  14.                 }  
  15.                 canRun=true;  
  16.             },600);  
  17.         }  
  18.     }  
由於滾動事件非常頻繁,稍微滾動一下就會觸發許多次,如果頻繁觸發的滾動,每一次都去檢查是否到頁面底部了再次造成了浪費。
於是設置一個開關,一次只能有一個觸發執行,並對執行設置計時一段時間再執行,執行完畢之後再解鎖。這就是函數節流

 函數節流應用的實際場景,多數在監聽頁面元素滾動事件的時候會用到。因爲滾動事件,是一個高頻觸發的事件。以下是監聽頁面元素滾動的示例代碼:

// 函數節流
var canRun = true;
document.getElementById("throttle").onscroll = function(){
    if(!canRun){
        // 判斷是否已空閒,如果在執行中,則直接return
        return;
    }

    canRun = false;
    setTimeout(function(){
        console.log("函數節流");
        canRun = true;
    }, 300);
};

 函數節流的要點是,聲明一個變量當標誌位,記錄當前代碼是否在執行。
 如果空閒,則可以正常觸發方法執行。
 如果代碼正在執行,則取消這次方法執行,直接return

 這個方法的作用是監聽ID爲throttle元素的滾動事件。
 當canRuntrue,則代表現在的滾動處理事件是空閒的,可以使用。
 通過關卡if(!canRun),等於就拿到了通行證。然後下一步的操作就是立馬將關卡關上canRun=false。這樣,其他請求執行滾動事件的方法,就被擋回去了。
 接着用setTimeout規定最小的時間間隔300,接着再執行setTimeout方法體裏面的內容。
 最後,等setTimeout裏面的方法都執行完畢,才釋放關卡canRun=true,允許下一個訪問者進來。

 這個函數節流的實現形式,需要注意的是執行的間隔時間是>=300ms。如果具體執行的方法是包含callback的,也可以將canRun=true這一步放到callback中。理解了函數節流的關卡設置重點,其實改起來就簡單多了。

demo地址https://wall-wxk.github.io/blogDemo/2017/02/15/throttleAndDebounce.html



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章