防抖和节流
防抖与节流的原理
本质上是优化高频率执行代码的一种手段
如:浏览器的 resize、scroll、keypress、mousemove 等事件在触发时,会不断地调用绑定在事件上的回调函数,极大地浪费资源,降低前端性能
为了优化体验,需要对这类事件进行调用次数的限制,对此我们就可以采用 防抖(debounce) 和 节流(throttle) 的方式来减少调用频率
定义
- 节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效
- 防抖: n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时
一个经典的比喻:
想象每天上班大厦底下的电梯。把电梯完成一次运送,类比为一次函数的执行和响应
假设电梯有两种运行策略 debounce 和 throttle,超时设定为15秒,不考虑容量限制
电梯第一个人进来后,15秒后准时运送一次,这是节流
电梯第一个人进来后,等待15秒。如果过程中又有人进来,15秒等待重新计时,直到15秒后开始运送,这是防抖
代码实现
// 使用
function showTop() {
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log("滚动条位置:" + scrollTop);
}
window.onscroll = debounce(showTop, 1000);
window.onscroll = throttle(showTop, 1000);
// ******************代码实现******************
function throttle(func, delay) {
let timer;
return function (...args) {
if (timer) return;
timer = setTimeout(() => {
func.apply(this, args);
clearTimeout(timer);
}, delay);
};
}
function debounce(func, delay) {
let timer;
return function (...args) {
if (timer) return clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}
几个问题
为什么使用高阶函数(函数嵌套)
通过使用方法 debounce(showTop, 1000)可以看拿出必须使用函数嵌套
为什么if (timer) return clearTimeout(timer);
这样第二次点击就会取消上一次的点击效果,和防抖定义相符合 "n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时"
为什么 func.apply(this, args);使用apply
根据用法可以看出,throttle(showTop, 1000); 要改变this指向