防抖
防抖技術即是可以把多個順序地呼叫合併成一次,也就是在一定時間內,規定事件被觸發的次數。
通俗一點來說,看看下面這個簡化的例子:
// 簡單的防抖動函式
function debounce(func, wait, immediate) {
// 定時器變數
var timeout;
return function() {
// 每次觸發 scroll handler 時先清除定時器
clearTimeout(timeout);//清除掉上一次的定時器回撥函式,上次事件也就不會執行了。在500ms內,再次滾動,那上次的就清除掉了,不會執行。
// 指定 xx ms 後觸發真正想進行的操作 handler
timeout = setTimeout(func, wait);
};
};
// 實際想繫結在 scroll 事件上的 handler
function realFunc(){
console.log("Success");
}
複製程式碼
採用了防抖動
window.addEventListener('scroll',debounce(realFunc,500));
封裝上面的函式,更簡潔
防抖動函式
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
var myEfficientFn = debounce(function() {
// 滾動中的真正的操作
}, 250);
// 繫結監聽
window.addEventListener('resize', myEfficientFn);
複製程式碼
防抖:
注意:上面的500ms,意思是:兩次滾動事件的相隔時間必須大於500ms才能觸發成功,而且是倒數第二次的事件觸發成功的。如果所有的事件觸發的時間間隔都小於500ms,那麼就不會觸發事件回撥函式了,只有最後一次的事件回撥能成功執行。
複製程式碼
節流(Throttling)
-
防抖函式確實不錯,但是也存在問題,譬如圖片的懶載入,我希望在下滑過程中圖片不斷的被載入出來,而不是隻有當我停止下滑時候,圖片才被載入出來。又或者下滑時候的資料的 ajax 請求載入也是同理。
-
這個時候,我們希望即使頁面在不斷被滾動,但是滾動 handler 也可以以一定的頻率被觸發(譬如 250ms 觸發一次),這類場景,就要用到另一種技巧,稱為節流函式(throttling)。
- 節流函式,只允許一個函式在 X 毫秒內執行一次。
-
與防抖相比,節流函式最主要的不同在於它保證在 X 毫秒內至少執行一次我們希望觸發的事件 handler。
-
與防抖相比,節流函式多了一個 mustRun 屬性,代表 mustRun 毫秒內,必然會觸發一次 handler ,同樣是利用定時器,看看簡單的示例:
// 簡單的節流函式
function throttle(func, wait, mustRun) {
var timeout,
startTime = Date.parse(new Date());//重點,這裡是在頁面載入後就執行的。不是等到滾動才執行。
console.log(startTime);
return function() {
var context = this,
args = arguments,
curTime = new Date();
clearTimeout(timeout);
// 如果達到了規定的觸發時間間隔,觸發 handler
if(curTime - startTime >= mustRun){
func.apply(context,args);
startTime = curTime;//重置開始時間startTime,把它設定成當前的時間
// 沒達到觸發間隔,重新設定定時器
}else{
timeout = setTimeout(func, wait);
}
};
};
// 實際想繫結在 scroll 事件上的 handler
function realFunc(){
console.log("Success");
}
// 採用了節流函式
window.addEventListener('scroll',throttle(realFunc,500,1000));
複製程式碼
上面簡單的節流函式的例子可以拿到瀏覽器下試一下,大概功能就是如果在一段時間內 scroll 觸發的間隔一直短於 500ms ,那麼能保證事件我們希望呼叫的 handler 至少在 1000ms 內會觸發一次。
注意:強調這句話:保證事件我們希望呼叫的 handler 至少在 1000ms 內會觸發一次。最多也是一次。也就是說,在所有滾動事件的每兩個相隔時間都加起來,從開始到結束滾動,每隔1000ms就是觸發一次。比如從開始到結束,共經歷1分鐘,每隔1秒呼叫一次,總共大概呼叫60次。
複製程式碼
參考連結: