目录
一、前言
二、节流(Throttle)
1、定义
2、使用场景
3、实现原理
4、代码示例
5、封装节流函数
三、防抖(Debounce)
1、定义
2、使用场景
3、实现原理
4、代码示例
5、封装防抖函数
四、异同点总结
一、前言
在JavaScript中,通常需要用到一些事件,比如:按钮的click事件、输入框的keydown事件、鼠标的mousemove事件、浏览器的resize事件等。
这些事件都可能被高频触发,会不断的执行回调函数,从而导致一些资源浪费,影响前端性能;
如何优化呢?
JavaScript中的节流(Throttle)与防抖(Debounce)是两种优化高频执行函数的方法;
主要用于控制函数执行的频率,从而减少不必要的资源消耗,提高页面性能;
二、节流(Throttle)
1、定义
节流是指,当事件被连续触发时,在设定的一段时间内,只执行一次该事件的回调函数;
也就是说,执行一次事件的回调函数后,等到间隔时间结束,若再触发该事件,才会再执行该事件的回调函数;
将高频执行变成每隔一段时间执行;
【举个例子】:
- 假设一个事件的间隔时间是3秒,当第一次触发了该事件,会执行该事件的回调函数,
- 3秒间隔内,再触发该事件,并不会再执行该事件的回调函数;
- 直到3秒钟过后,再触发该事件,才会再执行该事件的回调函数;
2、使用场景
(1)多次点击按钮
当一个搜索按钮被连续多次点击时,并不是每次点击都发送请求,会存在一个间隔时间,距上次点击完获取数据后,间隔几秒钟,再点击才会重新请求加载数据;
(2)频繁下拉刷新
同样的,当页面被频繁下拉刷新时,并不是每次下拉都发送请求重新加载数据,会存在一个间隔时间,距上次刷新完几秒钟后,再下拉才会重新请求加载数据;
3、实现原理
利用定时器setTimeout设置间隔时间;
- 每次执行事件的回调函数,都会添加一个新的定时器,到了设定时间再清除这个定时器;
- 通过判断定时器是否存在,即可得到设置的计时是否结束;
- 若定时器存在(未被清除),说明计时还未结束,本次不执行事件的回调函数;
- 若定时器不存在(已被清除),说明计时已经结束,本次要执行事件的回调函数;
4、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>节流与防抖</title>
</head>
<body>
<button class="zyl-button">点击按钮</button>
</body>
<script>
// 获取button按钮
var zyl_button = document.querySelector(".zyl-button");
// 使用节流
let timerId_1 = null;
zyl_button.addEventListener("click", function () {
if (!timerId_1) {
console.log("使用节流,每间隔3秒,再点击按钮才会被执行!");
timerId_1 = setTimeout(() => {
timerId_1 = null;
}, 3000);
}
})
</script>
</html>
- 按钮第一次被点击,执行打印输出;
- 接着连续点击不会打印输出;
- 直到距离上一次3秒钟过后,再点击才会继续打印输出;
5、封装节流函数
对节流函数进行封装,可以在需要的地方直接调用;
// 节流函数
function throttle(fn, time) {
let timerId_1 = null;
return function (...args) {
if (!timerId_1) {
fn.apply(this, args);
timerId_1 = setTimeout(() => {
timerId_1 = null
}, time);
}
};
}
在上述示例中使用封装的节流函数 :
<script>
// 获取button按钮
var zyl_button = document.querySelector(".zyl-button");
// 点击按钮的回调函数
function handleClick() {
console.log(this);
console.log("使用节流,每间隔3秒,再点击按钮才会被执行!");
}
// 点击按钮 使用节流函数
zyl_button.addEventListener('click', throttle(handleClick, 3000));
// 节流函数
function throttle(fn, time) {
let timerId_1 = null;
return function (...args) {
if (!timerId_1) {
fn.apply(this, args);
timerId_1 = setTimeout(() => {
timerId_1 = null
}, time);
}
};
}
</script>
三、防抖(Debounce)
1、定义
防抖:当事件被连续触发时,只有在最后一次触发事件后的延迟时间内没有再次触发,才会执行目标函数;
也就是说,事件被触发后,不会立即执行该事件的回调函数,若在该事件的延迟时间内,没有再触发该事件,则执行该事件的回调函数;
将高频执行变成在最后一次执行;
【举个例子】:
- 假设一个事件的延迟时间是3秒,当触发了该事件,则它的回调函数会在3秒后执行;
- 在这延迟的3秒期间,如果又触发了该事件,则会重新开始计时3秒钟;
- 如果又触发,就再重新计时,再触发,再重新计时......;
- 直到距离事件的触发时间(延迟时间),大于3秒钟,才会执行该事件的回调函数;
2、使用场景
(1)搜索框的输入搜索
每次输入内容都去请求数据,请求次数过多,非常浪费资源;可以设置一个输入延迟时间(1秒),输入内容1秒钟后,再去发送请求,获取搜索结果;通过减少请求次数,提升性能;
(2)文本编辑器的实时保存
没必要每次编辑内容都进行保存,同样可以设置一个延迟时间(3秒),编辑内容3秒钟后,再自动发送请求,保存数据;
3、实现原理
利用定时器setTimeout设置延迟时间;
- 每次事件触发时,先判断是否有延时定时器;
- 有则清除,没有则创建一个新的延时定时器;
- 在延时定时结束后,才会执行回调函数;
- 若延时时间未结束前(定时器存在),再次触发该事件,清除旧的定时器,并设置新的定时器,重新开始计时;
4、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>节流与防抖</title>
</head>
<body>
<input class="zyl-input" type="text"><br><br>
</body>
<script>
// 获取input框
var zyl_input = document.querySelector(".zyl-input");
// 使用防抖
let timerId_2 = null
zyl_input.addEventListener("keydown", function () {
if (timerId_2) {
clearTimeout(timerId_2);
}
timerId_2 = setTimeout(() => {
console.log("使用防抖,3秒延迟内,没有再次触发该事件,则该回调函数被执行!");
}, 3000);
})
</script>
</html>
- 在文本框中输入内容,打印输出并不会立即执行;
- 只有在输入停止3秒钟后才会打印输出;
5、封装防抖函数
对防抖函数进行封装,可以在需要的地方直接调用;
// 防抖函数
function debounce(fn, time) {
let timerId_2;
return function (...args) {
if (timerId_2) {
clearTimeout(timerId_2);
}
timerId_2 = setTimeout(() => {
fn.apply(this, args);
}, time);
};
}
在上述实例中使用防抖函数 :
<script>
// 获取input框
var zyl_input = document.querySelector(".zyl-input");
// 输入内容的回调函数
function handleInput() {
console.log(this);
console.log("使用防抖,3秒延迟内,没有再次触发该事件,则该回调函数被执行!");
}
// 输入内容 使用防抖函数
zyl_input.addEventListener('keydown', debounce(handleInput, 3000));
// 防抖函数
function debounce(fn, time) {
let timerId_2;
return function (...args) {
if (timerId_2) {
clearTimeout(timerId_2);
}
timerId_2 = setTimeout(() => {
fn.apply(this, args);
}, time);
};
}
</script>
四、异同点总结
异同点 | 节流 | 防抖 | |
---|---|---|---|
相同点 | 1.函数目标 | 都是为了优化事件处理,减少不必要的函数调用; | |
2.应用场景 | 用于处理频繁触发的事件,以减轻应用的性能负担; | ||
3.实现方式 | 都可以通过setTimeout定时器,设定时间间隔来实现; | ||
不同点 | 1.触发机制 | 节流在设定的时间间隔内只执行一次函数; | 防抖则是在事件停止触发后执行一次函数; |
2.执行时机 | 节流在事件触发时立即执行,但可能在时间间隔的末尾执行一次; | 防抖则是在事件停止触发后执行一次; | |
3.适用场景 | 节流适用于需要在一段时间内处理一次事件的场景,如定时刷新页面数据; | 防抖适用于需要在事件停止触发后执行一次操作的场景,如输入框的值变化; |
=========================================================================
每天进步一点点~!
记录一下 节流和防抖 这两个重要的技术~~!