在前端开发中遇到写频繁触发事件的事情,会引起一些性能上的问题;我们就需要用防抖节流进行处理,结合实际场景和防抖节流的原理,自行考虑要哪个。
以下就是频繁触发事件的一些操作:
- window 的 resize、scroll
- mousedown、mousemove
- keyup、keydown
- input输入框动态搜索数据
…
防抖 深入了解防抖
原理: 你尽管触发事件,但是我一定在事件触发 n 秒后才执行,如果你在一个事件触发的 n 秒内又触发了这个事件,那我就以新的事件的时间为准,n 秒后才执行,总之,就是要等你触发完事件 n 秒内不再触发事件,我才执行。
function debounce(func, wait, immediate) {
var timeout, result;
return function () {
var context = this;//func.apply(context, args)改变this的指向,指回func对象,否则的话就会指向window。
var args = arguments;//func.apply(context, args)把函数的参数也一起传过去,包括事件对象event,否则的话就会显示undefined
if (timeout) clearTimeout(timeout);
if (immediate) { //我不希望非要等到事件停止触发后才执行,我希望立刻执行函数,然后等到停止触发 n 秒后,才可以重新触发执行。用immediate判断是否要立即执行。
// 如果已经执行过,不再执行
var callNow = !timeout;
timeout = setTimeout(function(){
timeout = null;
}, wait)
if (callNow) result = func.apply(context, args)
}
else {
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
return result;//返回func的执行结果。
}
}
节流 深入了解节流
原理:无论你频繁触发多少次,每隔n秒内,只执行一次事件。
根据首次是否执行以及结束后是否执行,效果有所不同,实现的方式也有所不同。
我们用 leading 代表首次是否执行,trailing 代表结束后是否再执行一次。
关于节流的实现,有两种主流的实现方式,第一种是使用时间戳,第二种是设置定时器。
- 第一种事件会立刻执行,第二种事件会在 n 秒后第一次执行
- 第一种事件停止触发后没有办法再执行事件,第二种事件停止触发后依然会再执行一次事件
function throttle(func, wait, options) {
var timeout, context, args, result;
var previous = 0;
if (!options) options = {};//leading:false 表示禁用第一次执行;trailing: false 表示禁用停止触发后再执行一次;这两个参数不能同时设置
var later = function() {
previous = options.leading === false ? 0 : new Date().getTime();
timeout = null;
func.apply(context, args);
if (!timeout) context = args = null;
};
var throttled = function() {
var now = new Date().getTime();
if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0 || remaining > wait) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
};
return throttled;
}