为一个事件绑定函数后,存在这样一个问题:当事件连续出现时,绑定函数会联系触发。但我们并不想让函数连续出发执行,只想最后一个事件出现后触发一次绑定函数。
据一个场景例子,keydown
事件,当用户一直按着按键不放,绑定的函数就会不断地触发执行。用户体验差。这个时候debounce
函数便派上用场。
先看一下debounce
函数的原型:
debounce(function, wait, immediate)
debounce
函数的大致思想是返回一个函数,在用户指定延时时间内,如果该函数被重复调用,该函数不会执行,并且重新开始延时,只到延时结束,该函数才被执行。
underscore.js和lodash.js这类知名的javascript库都提供了debounce
。
下面自己试着写了一下:
function debounce(func, delay) {
var timeout;
return function () {
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(function() {
func();
}, delay);
}
}
var log = function() {
console.log('haha');
}
var dlog = debounce(log, 1000);
dlog();
dlog();
dlog();
dlog(); // 只有这次调用才会输出‘haha'
下面参考[这里],写一个改进版的:
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
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);
};
};
// Usage
var myEfficientFn = debounce(function() {
// All the taxing stuff you do
}, 250);
window.addEventListener('resize', myEfficientFn);