前言
防抖和节流是面试常问的热点。如果能够很好的理解防抖和节流的要点,确实可以说明面试者具备了一定的前端知识。
需要注意的三个点
- 闭包 防抖和节流函数本质都是闭包函数。闭包函数返回了一个函数,返回函数可以调用闭包环境中的变量。
// 防抖或节流,以防抖函数为例
function debounce(delay, callback){
// 闭包环境中的变量
let lastTime = 0;
// 闭包中的返回函数
return function (){
lastTime = Date.now()
...
}
}
- 延时执行 延时执行一般通过定时器实现。其中节流也可以通过时间戳实现。
// 时间戳 currentTime, lastTime
function throttle(delay, callback) {
let lastTime = 0;
return function () {
// 获取当前时间
const currentTime = new Date.now();
if (currentTime - lastTime > delay) {
...
lastTime = currentTime;
}
};
}
// 定时器
function throttle(delay, callback) {
let timer;
return function () {
if (timer) return
timer = setTimeout(()=>{
...
timer = null
}, delay)
lastTime = currentTime;
};
}
- 函数形参 arguments 和绑定 this 防抖和节流函数在绑定 js 事件,触发后,参数需要传递给 callback 函数,并且需要绑定 this。其中如果使用了箭头函数,需要注意箭头函数没有this 和arguments。 this 为箭头函数所在的执行上下文中的 this, arguments 为箭头函数所在父函数的 arguments。
// 以节流函数为例
function throttle(delay, callback){
...
return function(){
// this 指的js 事件触发时的执行环境;arguments 为事件回调函数的参数
callback.apply(this, arguments)
}
}
自己实现的防抖和节流函数
// 防抖
function debounce(delay,callback){
let timer
return function(){
clearTimeout(timeout)
timer = setTimeout(() => {
callback.apply(this, arguments)
}, delay)
}
}
// 节流-定时器版
function throttle(delay, callback) {
let flagExec = true
return function () {
if (!flagExec) {
return
}
flagExec = false
setTimeout(() => {
callback.apply(this, arguments)
flagExec = true
}, delay)
}
}
// 节流-时间戳版
function throttle(delay, callback) {
let lastTime = 0;
return function () {
// 获取当前时间
const currentTime = Date.now();
if (currentTime - lastTime > delay) {
callback.apply(this, arguments)
lastTime = currentTime;
}
};
}
// 调用,本质上是需要执行一次 debounce 和 throttle 函数
document.onmousemove = debounce(1000, function(args){console.log(123)});
document.onmousemove = throttle(1000, function(args){console.log(123)});
进阶
防抖和节流还可以功能更丰富一些,比如:取消,事件触发立即执行一次,停止触发再执行一次等。 有兴趣的可以翻看 throttle-debounce 库源码, 这里不再赘述。
其他
欢迎大家关注微信公众号:赵公子聊前端。