防抖(debounce)和节流(throttle):
本质都是为了控制函数在高频事件下的触发次数,降低函数执行频率,节省计算资源,提高性能。不然的话,会容易造成网络阻塞,页面卡顿,或者数据错乱覆盖等情况。
两者区别:
防抖:
高频事件下,控制执行最后一次
节流:
高频事件下,控制(函数)执行的次数。也就是一个单位时间内,只允许执行1次。
实现一个简单的防抖:
<body>
<input type="text" />
<script>
let inp = document.querySelector("input");
// 防抖 debounce(callback,delay);
inp.oninput = debounce(function () {
// 在这里可以进行逻辑操作
console.log(this.value);
...
}, 2000);
// 通过闭包实现防抖
function debounce(fn, delay) {
let timer = null;
return function () {
if (timer !== null) {
clearTimeout(timer);
}
timer = setTimeout(() => {
// 箭头函数没有自己的this,改变指向,使其指向input。同时执行fn函数
fn.call(this);
}, delay);
};
}
</script>
</body>
案例分析:
第一次点击了输入框,输入内容后,开启定时器,timer会得到一个值。(这个值代表着等待队列);
第二次输入内容时,会进入if判断(已经有值,不为null)。执行清除定时器。重新生成一个定时器,timer得到一个新的值;
如果在3秒内,不停的输入内容,则会不停地触发事件——清除上一个定时器,开启新的定时器;
直到最后一次输入结束,最后一个定时器等待3秒后,输出结果。
可以看出,防抖的关键点在于:利用闭包,在返回的函数体里,通过不断开启和清除定时器,在限定时间内不断点击,仍然只执行最后一次
实现简单版的节流:
第一种方式:通过时间戳实现
间隔时间 wait
初始时间 start-time
最新时间 new-time (事件被触发时计算)
当2者时间差 < wait , 不能执行事件函数
当2者时间差 > = wait , 执行操作
案例分析
<style>
body {
height: 2000px;
}
</style>
<script>
window.onscroll = function (e) {
test();
};
// 执行节流函数
let test = throttle(function () {
// 在这里进行逻辑操作
console.log("hello");
}, 2000)
// 节流
function throttle(fn, wait) {
// 获取初始时间
let start = 0;
return function () {
let now = new Date().getTime();
// 判断前后时间戳的差值
if (now - start < wait) return;
fn();
// 重新设置初始时间
start = now;
};
}
</script>
第二种方式: 通过控制锁的状态,实现节流
<script>
window.onscroll = throttle(function () {
console.log("hello world");
}, 3000);
// 通过定时器实现节流
function throttle(fn, wait) {
let lock = true;
return function () {
if (lock) {
// 关锁
lock = false;
// 通过定时器开锁
setTimeout(() => {
lock = true;;
fn();
}, wait);
}
};
}
</script>
第一次,lock=true ,进入if判断,关锁---等待3秒,开锁,执行操作;
第二次,lock=true ,进入判断,关锁---等待3秒,开锁,重复操作...