持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情
☀ 前言
在很多小伙伴的印象中 节流与防抖 似乎只有在面试过程中才能见到,其实并非如此。在我们的日常开发过程中,也常常可以用到它们 来优化项目性能。
那么接下来我们来从 日常 开发角度,来学习 节流与防抖
🎉 防抖
💕 场景再现
我们不谈概念,毕竟概念实在让人疯狂。我们就举个生活中的例子。
小明是一位码农,每天都要坐电梯上下班,并且小明暗恋着同层的一位女神, 于是小明每天都会比女神提前一分钟出发,为女神占电梯。
假设 当小明 按下电梯键后,电梯门打开后会在3秒后默认关闭。 于是小明在等待女神的期间, 会不停的按击电梯键。
我们设想一个场景,假设小明连续 按击 电梯键 2次, 那么电梯门会在3秒后连续关闭 2次么?
我想不会,至少我没见过。我相信在座的各位和小明都没见过这种电梯。 就这样在小明的不断努力下,女神坐上了电梯,并友好的对着小明唱了一首 听我说谢谢你。
💕延伸
上面的场景就是一个 防抖 的例子。 有2个关键点
- 3秒钟(单位时间)
- 电梯关门 (执行的事件)
ps: 有杠精小伙伴问电梯开门咋被忽略了,这个么 emmm
其实防抖可以简单的理解为: 单位时间内事件多次触发会被重置
💕实际场景
小明送完女神,刚坐到办公位,就受到了 夺命连环call, 说是一个用户 一秒钟点击 提交按钮 100次,导致产生的 100条记录。 小明听到 惊呆了, 只能默默的写了下面的代码.
<button onclick="sendInfo()">点击发送</button>
👣 步骤1: 编写 sendInfo 函数, 并连续点击 10次
function sendInfo () {
console.log('点击一下')
}
于是 点击十次 * 10
👣步骤2: 添加定时器控制时间, 并连续点击 10次
function debounce (fn, wait) {
setTimeout(()=> {
fn()
}, wait)
}
function sendInfo() {
debounce(() => {
console.log('点击一次')
}, 200)
}
然后小明发现并没有什么效果, 只是延迟了 200ms, 思索了一下.
👣步骤3: 清空定时器, 保证单位时间只执行一次
function debounce (fn, wait) {
let timer;
clearTimeout(timer);
timer = setTimeout(()=> {
fn()
}, wait)
}
function sendInfo() {
debounce(() => {
console.log('点击一次')
}, 200)
}
结果发现 清空了,又好像没有清空。原因很简单: 每次执行 debounce 都会新建 timer变量, 老的
👣步骤4: 最后一步,请叫我 小明神
function debounce (fn, wait) {
let timer;
return function () {
clearTimeout(timer)
timer = setTimeout(()=> {
fn()
}, wait)
}
}
const db = debounce(() => {
console.log("点击了一下")
}, 200)
function sendInfo() {
db()
}
这里可以很清晰的看到, debounce 返回一个函数, 此时 timer 变量 处于 debounce 的函数作用域中。所以在 db每一次 执行过程中, timer都是同一个。
🎉 小结
这里是一个最简易的防抖函数,在日常工作中,可能有很多变种。例如立即执行等等, 就好比 小明送女神礼物, 一束装扮精美的花。 但是再精美 它还是一束花 !而在我们日常开发中, 也有很多场景可以用到防抖如: 输入框输入发送请求,窗口移动等
🎉 节流
💕 场景再现
老样子, 我们不谈概念。直接 编个故事
小明无意间知道了女神爱养🐟, 为了能和女神套进关系。小明将养🐟列为 人生 第一小目标。 为了能够让鱼儿快快长大。 小明发明了喂食神器, 每 30秒 投喂一次。 可是好景不长😂, 鱼儿全死光了。由于设计缺陷,每30秒投喂的功能无法改变 (如mousemove的频率无法修改一样), 小明只能再次发明了 喂食挡板,将投喂的食物进行阻挡(如代码中阻止事件执行)。 小明并将此发明 分享给了女神,于是女神友好的对着小明唱了一首 听我说谢谢你
💕延伸
上面的场景就是一个 节流 的例子。 有个关键点
- 单位时间只执行一次(如喂鱼)
其实节流可以简单的理解为: 单位时间内事件只能触发一次
💕实际场景
小明接到一个需求, 记录用户的鼠标移动热点图, 要求5秒钟记录一次。
💕代码实现
小明回想到了前一天写的防抖函数,变得犹如神助, 于是分分钟写出来期望中得代码。
function throttle(fn, wait) {
let oTime = 0;
return function (...arg) {
let nTime = new Date();
if (nTime - oTime > wait) {
fn(...arg);
oTime = nTime;
}
}
}
function pushPosition(e) {
const {pageX, pageY} = e;
console.log(`记录坐标x:${pageX} y:${pageY}`)
}
const db = new throttle(pushPosition, 5000)
document.addEventListener('mousemove', (e) => {
db(e)
})
我们可以看到和防抖函数一样, 具体关键点是触发时间。 只不过唯一的区别, 节流会在单位时间的触发一次,而不会重置。
🎉 小结
节流在日常开发中使用场景也有很多: 例如 鼠标移动的节流, 鼠标滚动的节流等等
🌹 总结
以上是个人较为浅显的理解,如有不对的地方,请指出😊。
- 防抖: 单位时间内事件多次触发会被重置 适用场景: 按钮的重复点击, 输入框输入发送请求 等
- 节流: 单位时间内事件只能触发一次 适用场景: 鼠标移动的节流, 鼠标滚动的节流
当然,日常工作中,有很多优秀的工具提供了相应的方法,它们更优秀,更强壮。我们可以直接使用它,但是 我们还是需要理解它。 知己知彼百战不殆