一、啥子是防抖节流
首先我们来看一个例子
我想要搜索一个MacBook:
当我输入m时,为了更好的用户体验,通常会出现对应的联想内容,这些联想内容通常是保存在服务器的,所以需要一次网络请求;
当继续输入ma时,再次发送网络请求;
那么macbook一共需要发送7次网络请求;
这大大损耗我们整个系统的性能,无论是前端的事件处理,还是对于服务器的压力;
但是我们需要这么多次的网络请求吗?不需要,正确的做法应该是在合适的情况下再发送网络请求;
比如如果用户快速的输入一个macbook,那么只是发送一次网络请求;
比如如果用户是输入一个m想了一会儿,这个时候m确实应该发送一次网络请求;
也就是我们应该监听用户在某个时间,比如500ms内,没有再次触发时间时,再发送网络请求;
这就是防抖的操作:只有在某个时间内,没有再次触发某个函数时,才真正的调用这个函数;
当事件触发时,相应的函数并不会立即触发,而是会等待一定的时间;
当事件密集触发时,函数的触发会被频繁的推迟;
只有等待了一段时间也没有事件触发,才会真正的执行响应函数;
我们用一副图来理解一下它的过程;
防抖的应用场景很多:
-输入框中频繁的输入内容,搜索或者提交信息;
-频繁的点击按钮,触发某个事件;
-监听浏览器滚动事件,完成某些特定操作;
-用户缩放浏览器的resize事件;
总之,密集的事件触发,我们只希望触发比较靠后发生的事件,就可以使用防抖函数;
接下来再看一个例子:
在飞机大战的游戏中,我们按下空格会发射一个子弹:很多飞机大战的游戏中会有这样的设定,即使按下的频率非常快,子弹也会保持一定的频率来发射;(其实很多的街机游戏都是这样的,普通攻击有一个最高的频率);
比如1秒钟只能发射一次,即使用户在这1秒钟按下了10次,子弹会保持发射一颗的频率来发射;
但是事件是触发了10次的,响应的函数只触发了一次;
这就是节流的操作:在某个时间内(比如500ms),某个函数只能被触发一次;
我们用一副图来理解一下它的过程;
节流的应用场景:
-监听页面的滚动事件;
-鼠标移动事件;
-用户频繁点击按钮操作;
-游戏中的一些设计;
总之,依然是密集的事件触发,但是这次密集事件触发的过程,不会等待最后一次才进行函数调用,而是会按照一定的频率进行调用;
二、防抖节流的代码实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="save-button">保存</button>
<script>
// 防抖:舍弃在规定时间外做的高频操作
// 闭包,使得timer为局部变量,不污染全局
function debounce(time) {
let timer = null;
return function() {
clearTimeout(timer);
timer = setTimeout(() => {
console.log('300ms after');
}, time);
}
}
// 小于300ms时间内的高频操作被舍弃
window.addEventListener('resize', debounce(300));
// 节流:在规定的时间内完成之后才能进行下一次操作
function throttle(fn, time) {
let active = true;
// 未保存前,允许点击保存操作
return function() {
if (active) {
// 保存之后,未完成相关操作之前不允许重新保存操作
active = false;
setTimeout(() => {
fn();
// 保存操作完成之后,允许后续点击操作
active = true;
}, time);
}
}
}
const saveButton$ = document.getElementById('save-button');
saveButton$.addEventListener('click', throttle(function() {
console.log('保存点击!');
}, 500))
</script>
</body>
</html>