不论在日常工作中,还是在面试过程中,防抖节流
总是会时不时的出现在我们的视野里。在日常使用的时候,可能会直接使用第三方库封装好的方法,比如 lodash
中的防抖方法 .debounce 和节流方法 .throttle。抑或是使用开发团队的小伙伴们封装好的方法。
在忙碌的工作中,也许小伙伴们知道它们的作用,但是对其中的原理逐渐陌生。今天我们就把这两个 老朋友
请出来,再来一起看看是如何实现的吧~
节流方法:throttle
什么是节流
用一句话概括节流:
在规定的延时时间内,不管你执行多少次,我都只认第一次。
节流的实现
/**
* 节流函数
* @param fn
* @param delay
*/
function throttle (fn, delay) {
// 上一次的调用时间
let lastTime = 0
// 将throttle结果以函数形式返回
return function () {
// 保存执行时上下文
const context = this
// 保存调用throttle结果函数时传入的参数
const args = arguments
// 本地调用的时间
const time = new Date()
// 如果本次调用时间减去上一次的调用时间大于延迟时间,则触发传入的fn
if (time - lastTime > delay) {
lastTime = time
fn.apply(context, args)
}
}
}
防抖方法:debounce
什么是防抖
用一句话概括防抖:
在规定的延时时间内,不管你触发多少次回调,都只认最后一次。
防抖的实现
/**
* 防抖
* @param fn
* @param delay
*/
function debounce (fn, delay) {
// 保存延时
let timer = null
// 将debounce的处理结果以函数形式返回
return function () {
// 保存执行时上下文
const context = this
// 保存执行时传入的参数
const args = arguments
// 如果存在定时器,则将其清除
timer && clearTimeout(timer)
// 设置新的定时器,在计时结束后触发回调
timer = setTimeout(() => {
fn.apply(context, args)
}, delay)
}
}
防抖的弊端
防抖与节流的目的,都是在一定时间内限制回调函数被调用的次数,从而在一定程度上提升性能。
但是防抖存在一个弊端,那就是如果在 delay
指定的时间内不断触发防抖,就会导致回调函数迟迟不会有响应。只有在你 停手
之后,经过 dealy
这段时间后,回调函数才会有响应。
既然如此,如果我们能在一开始就触发回调,然后在后续频繁的操作里保持防抖的特性,岂不是美滋滋~
加强版的节流方法:strongerThrottle
回顾我们之前所实现的 节流
方法,它不正是在一开始就可以立即调用回调函数的么?既然如此,我们可以使用 throttle
方法来对 debounce
方法进行优化,实现一个加强版的节流方法。
/**
* 更健壮的节流,结合了防抖
* @param fn
* @param delay
*/
function strongerThrottle (fn, delay) {
// 保存计时器与最后一次调用时间
let timer = null
let lastTime = 0
// 将调用strongerThrottle的结果以函数形式返回
return function () {
// 保存执行上下文
const context = this
// 保存传入的参数
const args = arguments
// 保存当前调用时间
const time = new Date()
// 如果当前调用的时间减去最后一次调用的时间小于延迟时间,则设置定时器
if (time - lastTime < delay) {
// 如果存在定时器,则先清空
timer && clearTimeout(timer)
// 设置新的定时器,在计时结束后触发回调
timer = setTimeout(function () {
lastTime = time
fn.apply(context, args)
}, delay)
} else {
// 如果超出时间,则给出响应
lastTime = time
fn.apply(context, args)
}
}
}