防抖
开发中,经常会遇到一些频繁触发的事件。
应用场景
- window: resize、scroll
- mousemove、mouseodown
- keyup, keydown
我们会明明鼠标只是移动一次,可能就会触发五六次。如果我们请求数据,1次就会请求这么多次,多么的浪费带宽。我们需要借助一些工具,使得我们能够控制触发的频率。
防抖
防抖就是我们的事件触发只会 n 秒后触发一次,如果你在事件触发当中,又触发了事件,事件的最终触发触发事件将会延迟到最后一次触发的 n 秒之后触发。
实现原理
原理就是:第一次触发我们开启一个delay秒的定时器,定时器到了我们就触发这个事件。
第一次 timer = 1. 但是又一次触发了,这个时候 if (timer) 就会执行,清除 timer 。
重新开启一个 delay 的定时器继续等待。一次又一次。
第一版本实现
注意: 真正的 this 指向,event事件对象都是在返回的包装还是当中。我们需要重新指回 func 函数中。
function debounce(func, delay) {
var timer;
return function () {
var context = this,
args = arguments;
if (timer) clearTimeout(timer);
timer = setTimeout(function () {
func.apply(context, args);
}, delay);
}
}
第二版 (立即执行事件)
immediate 如果需要立即执行,如果已经执行过,不再执行。
function debounce(func, delay, immediate) {
var timer;
return function () {
var context = this,
args = arguments;
if (timer) clearTimeout(args);
if (immediate) {
var callNow = !timer;
timer = setTimeout(function () {
timer = null;
}, delay);
if (callNow) func.apply(context, args);
} else {
// 不用立即执行
timer = setTimeout(function () {
func.apply(context, args);
}, delay);
}
}
}
返回值
function debounce(func, delay, immediate) {
var timer, result;
return function () {
var context = this,
args = arguments;
if (timer) clearTimeout(args);
if (immediate) {
var callNow = !timer;
timer = setTimeout(function () {
timer = null;
}, delay);
if (callNow) result = func.apply(context, args);
} else {
// 不用立即执行
timer = setTimeout(function () {
func.apply(context, args);
}, delay);
}
return result;
}
}
中途取消
function debounce(func, delay, immediate) {
var timer, result;
var debounced = function () {
var context = this,
args = arguments;
if (timer) clearTimeout(args);
if (immediate) {
var callNow = !timer;
timer = setTimeout(function () {
timer = null;
}, delay);
if (callNow) result = func.apply(context, args);
} else {
timer = setTimeout(function () {
func.apply(context, args);
}, delay);
}
return result;
}
debounced.cancel = function () {
clearTimeout(timer);
timer = null;
}
return debounced;
}