函數節流和函數防抖
函數節流概念: 函數預先設定一個執行周期,當調用動作的時刻大于等于執行周期則執行該動作,然後進入下一個新周期
比如在做網頁的時候有個需求,就是浏覽器視窗改變的時候需要改一些頁面元素大小,于是乎很自然的想到了window的resize事件
<script>
var n = 0;
function resizeHandler () {
console.log(n++);
}
window.onresize = resizeHandler
</script>
效果随着視窗大小改變不停列印n的值
使用函數節流
<script>
var n = 0;
function resizeHandler () {
console.log(n++)
}
function throttle (method, delay) {
var timer = null;
return function () {
var context = this;
var args = arguments;
clearTimeout(timer);
timer = setTimeout(() => {
method.apply(context, args)
}, delay);
}
}
window.onresize = throttle(resizeHandler, 500);//因為傳回函數句柄,不用包裝函數了
</script>
視窗大小改變,不斷列印n的值,但不要一直列印,500ms内如果沒有繼續拖動,則列印值
對于函數節流,有如下幾個場景:
- 遊戲中的重新整理率
- DOM元素拖拽
- Canvas畫筆功能
函數防抖:函數執行過一次後,在等待某時間段内不能再次執行;在等待時間内觸發此函數,則重新計算等待時間
<script>
var n = 0;
function debounce (method, wait, flag) {
var timer = null;
var context, args, result, timestamp;
var later = function () {
var oDate = new Date();
var last = oDate.getTime() - timestamp; // 計算第一次時間戳與目前時間戳的內插補點。
if (last < wait && last >= 0 ) { // 在等待時間内觸發此函數,重新計時。
timer = setTimeout(later, wait - last);
} else {
timer = null;
if (!flag) { // 限制flag 為true時,執行回調函數。
result = method.apply(context, args);
if (!timer) {
context = args = null
}
}
}
}
return function () {
var oDate = new Date();
var callNow = flag && !timer; // 代表第一次調用立即執行。
timestamp = oDate.getTime(); // 記錄下目前時間戳
context = this;
args = arguments;
if (!timer) { // 第一次觸發時,timer為空,進入此分支
timer = setTimeout(later, wait);
}
if (callNow) { // 第一次觸發且flag為true,進入此分支
result = method.apply(context, args);
context = args = null
}
return result;
}
}
window.onscroll = debounce (function () {
console.log(1)
}, 500, false)
</script>
此次封裝支援兩種形式:
flag為true時,連續事件觸發時,隻會在第一次觸發的時候執行回調。
flag為false時,連續事件觸發時,隻會在最後一次觸發的時候執行回調。
對于函數防抖,有以下幾種應用場景:
- 給按鈕加函數防抖防止表單多次送出。
- 對于輸入框連續輸入進行AJAX驗證時,用函數防抖能有效減少請求次數。
-
判斷scroll是否滑到底部,滾動事件+函數防抖
總的來說,适合多次事件一次響應的情況
歡迎大家點贊和評論,如有不足之處請大神指出,剛入門,請多多指教。