节流
概念简述
在一段时间内只取用第一次的调用。
节流的字面意思就是当一次通行之后到达了阈值,就会开启节流阀门限制你通行。
形象记忆
就像你来到了某个人流量特别大的旅游景点,在一定的时段内,先来的人可以通行,到了人流限制点之后,人员均不得入内,得等待下一波放行时间。
实现原理
节流是借助闭包来实现的,通过闭包来缓存上一次触发回调的时间与当前时间进行比对限制回调执行。
重点
- 闭包:返回一个函数,缓存上次调用时间;
- 上次调用时间与本次调用时间比对;
- 触发传入的回调:使用apply将调用时的this指向回调函数,将arguments传入回调;
js
// fn是我们需要包装的事件回调, interval是时间间隔的阈值
function throttle(fn, interval = 200) {
// last为上一次触发回调的时间
let last = 0
// 将throttle处理结果当作函数返回
return function () {
// 记录当前调用时间戳
let now = +new Date()
// 判断上次触发的时间和本次触发的时间差是否小于时间间隔的阈值
if (now - last >= interval) {
// 如果时间间隔大于我们设定的时间间隔阈值,则执行回调
last = now;
// this: 调用时的上下文, arguments 调用时传入的参数
fn.apply(this, arguments);
}
}
}
// 用throttle来包装scroll的回调
const better_scroll = throttle(() => console.log('触发了滚动事件'), 1000)
document.addEventListener('scroll', better_scroll)
使用场景推荐
- 滚动事件处理
- 鼠标移动事件
- 其他限制请求频率等需要控制函数执行频率的场景
防抖
概念简述
在一段时间内只取用最后一次的调用。
防抖这个概念很形象,防止你手抖误操作,在一段时间还给你改正的机会,会以你最后一次操作为准。
形象记忆
在高考填写志愿的时候,会你足够的时间让你慎重考虑之后填写,在填写期间你可以随意改变志愿,最终会以你最后一版志愿为准。
实现原理
防抖也是借助闭包来实现的,通过闭包来缓存定时器,调用将会被延迟执行,在这个延迟等待过程中如果你重复调用,上次的等待将会中断弃用,开启下一轮延迟执行。
重点
- 闭包:返回一个函数,缓存延迟定时器
- 回调执行时清除上一个定时器,setTimeout延迟执行本次回调
- 触发传入的回调:使用apply将调用时的this指向回调函数,将arguments传入回调
js
// fn是我们需要包装的事件回调, delay是每次推迟执行的等待时间
function debounce(fn, delay = 200) {
// 定时器
let timer = null
// 将debounce处理结果当作函数返回
return function () {
// 每次事件被触发时,都去清除之前的旧定时器
timer && clearTimeout(timer)
// 设立新定时器
timer = setTimeout(function () {
// this: 调用时的上下文, arguments 调用时传入的参数
fn.apply(this, arguments)
}, delay)
}
}
// 用debounce来包装scroll的回调
const better_scroll = debounce(() => console.log('触发了滚动事件'), 1000)
document.addEventListener('scroll', better_scroll)
使用场景推荐
- 输入框搜索
- 按钮点击防止重复提交
- 其他需要等待用户停止操作后再执行的场景
杂交版节流
不知道大家最近都玩过植物大战僵尸杂交版没有,各种类型的杂交植物把植物大战僵尸又推向了新的高点。咱们也可以推出一个杂交版的节流(或者是杂交版防抖?此文统称为杂交版节流),融合了节流和杂交,妥妥的升级。
只要你弄懂了节流和防抖的原理,相信杂交版的节流你会很熟悉,杂交版的节流就是将防抖的逻辑增添进来了,所以它融合了节流和防抖的优点,在一段时间内,第一次操作将会被执行,如果你在这段时间内有别的操作,将会取最后一次的操作再执行一次,相当于是一个双保险。
js
// fn是我们需要包装的事件回调, interval是时间间隔的阈值
function throttlePlus(fn, interval) {
// last为上一次触发回调的时间, timer是定时器
let last = 0, timer = null
// 将throttle处理结果当作函数返回
return function () {
// 记录本次触发回调的时间
let now = +new Date()
// 节流
if (now - last >= interval) {
// 如果时间间隔超出了我们设定的时间间隔阈值,那就不等了,无论如何要反馈给用户一次响应
last = now
fn.apply(this, arguments)
} else {
// 防抖
// 如果时间间隔小于我们设定的时间间隔阈值,则为本次触发操作设立一个新的定时器
clearTimeout(timer)
timer = setTimeout(function () {
last = now
fn.apply(this, arguments)
}, interval)
}
}
}
// 用新的throttle包装scroll的回调
const better_scroll = throttlePlus(() => console.log('触发了滚动事件'), 1000)
document.addEventListener('scroll', better_scroll)
码上掘金
这是一个点击按钮,按钮的数字会加一的例子,分别使用了节流、防抖、杂交版节流三种方式,让你可以体验一下这三种场景。