一、为什么要进行防抖与节流?
在前端开发的过程中,我们经常会需要绑定一些持续触发的事件,如 resize、scroll、mousemove 等等,但有些时候我们并不希望在事件持续触发的过程中那么频繁地去执行函数。
就比如这样:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>防抖与节流</title>
<style>
.box {
width: 200px;
height: 200px;
background-color: aqua;
margin: 100px auto;
}
</style>
</head>
<body>
<div class="box">
<span class="count">1</span>
</div>
</body>
<script>
const box = document.querySelector('.box');
let counts = document.querySelector('.count')
let count = 0;
box.addEventListener('mousemove', function () {
count++;
console.log(count + '触发了');
counts.innerHTML = count;
})
</script>
</html>
在上述代码中,div 元素绑定了 mousemove 事件,当鼠标在 div区域中移动的时候会持续地去触发该事件导致频繁执行函数自增。效果如下
通常这种情况下我们怎么去解决的呢?一般来讲,防抖和节流是比较好的解决方案。
二、防抖:
2.1 是什么?
- 所谓防抖,就是指触发事件后 n 秒后才执行函数,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
- 比喻:防抖相当于回城,每次被打断,就需要重新执行回城的操作,只有真正不受干扰时才能完成回城;
2.2 代码实现:
简单版本的实现:
function debounce(func, delay) {
let timer = null;
return function () {
let context = this; // 保存this指向
let args = arguments; // 拿到event对象
clearTimeout(timeout)
timeout = setTimeout(function () {
func.apply(context, args)
}, wait);
}
}
三、节流:
3.1 是什么?
- 所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率。
- 比喻:节流相当于技能冷却,在施放了一次技能操作后,只有等到规定时间后才能施放下一次技能,这期间就是键盘或鼠标按烂了也无法施放技能,即施放技能的频率是定死的。
3.2 代码实现:
使用定时器写法,delay
毫秒后第一次执行,第二次事件停止触发后依然会再一次执行
function throttled2(fn, delay = 500) {
let timer = null
return function (...args) {
if (!timer) {
timer = setTimeout(() => {
fn.apply(this, args)
timer = null
}, delay);
}
}
}
四、使用场景
防抖:
- 搜索框搜索输入。只需用户最后一次输入完,再发送请求
- 手机号、邮箱验证输入检测
- 窗口大小
resize
。只需窗口调整完成后,计算窗口大小。防止重复渲染
节流:
- 滚动加载,加载更多或滚到底部监听
- 搜索框,搜索联想功能