應用場景瀏覽器
咱們常常須要監聽滾動條滾動或者鼠標的移動,可是瀏覽器觸發這類事件的頻率很是高,可能10幾毫秒就觸發一次,有的時候咱們只須要處理函數執行一次,好比文本輸入驗證,執行屢次處理函數反而不必。閉包
常規實現,以監聽 scroll 事件爲例app
window.onscroll = function () {
//滾動條位置
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滾動條位置:' + scrollTop);
}
解決方法:函數
減小DOM操做的頻度,也就是稀疏處理函數的執行頻率,解決方法就是函數防抖以及函數分流。函數防抖表示只執行一次處理函數,函數分流指下降處理函數的執行頻率。this
指屢次觸發事件後,事件處理函數只執行一次。具體思路就是延遲處理函數,若是設定的時間到來以前又一次觸發了事件,就清除上一次的定時器,從新定時。spa
簡單來講,就是當一個動做連續觸發時,只執行最後一次。code
簡單實現的例子:blog
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);
應用場景:
(1)搜索框輸入。只需用戶最後一次輸入完,在發送請求;
(2)手機號、郵箱驗證輸入檢測;
(3)窗口大小Resize。只需窗口調整完成後,計算窗口大小,防止重複渲染。
不適用:作圖片懶加載時,須要經過滾動位置實時顯示圖片時,若是使用防抖函數,懶加載函數就會不斷被延遲,只有停下來的時候纔會被執行,防抖函數對於這種須要實時觸發事件的狀況就顯得不是很友好了。
觸發事件函數後,短期內沒法連續調用,只有上一次函數執行後,過了規定的時間間隔,才能進行下一次的函數調用。
原理:對處理函數進行延時操做,若設定的延時到來以前,再次觸發事件,則清除上一次的延時操做定時器,從新定時。
簡單實現的例子:
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);
應用場景:
(1)滾動加載,加載更多或滾動到底部監聽;
(2)高頻點擊提交,表單重複提交 。
函數防抖與函數分流的思想都是經過設置定時器控制函數的執行頻率。
區別:
(1)函數防抖在一段連續的操做結束後,處理回調函數,利用setTimeout和clearTimeout實現;
函數節流在一段連續的操做中,每一段時間只執行一次。
(2)函數防抖關注必定時間連續觸發,只在最後執行一次,而函數節流側重於一段時間內只執行一次。