首先得明白防抖和节流解决了:事件处理函数调用的频率无限制,加重浏览器的负担,导致用户体验非常差,甚至卡死
一、防抖(debounce)
概念
在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时;
简而言之就是执行多次操作事件只在规定的时间内只执行最后一次
应用场景
- 文本框输入搜索(连续输入时避免多次请求接口)
- 在进行窗口的resize、scroll监听操作
- 高频点击提交,表单重复提交
实现原理
设置一个定时器,在指定时间间隔内运行代码时,清除上一次的定时器,并设置新的定时器,直到函数请求停止并超过时间间隔才会执行。
代码示例
- 实现文本框输入搜索
先看下没使用防抖的操作:
[图片上传失败...(image-c1b504-1685071573959)]
不使用防抖的情况: <input type="text" id="search" />
<script>
const searchHandle = document.getElementById("search");
searchHandle.addEventListener("input", function () {
console.log(this.value);
});
</script>
很明显,如果一直监听输入值查询接口的话,那必然会出现性能问题!
使用防抖的操作:
[图片上传失败...(image-28d30f-1685071573959)]
使用防抖的情况: <input type="text" id="search" />
<script>
const searchHandle = document.getElementById("search");
function debounce(func, delay) {
let timer = null;
return function () {
if (timer) clearTimeout(timer); // 每次监听输入值,都会去判断是否还有timer,有就清除timer
timer = setTimeout(() => {
func.call(this);
}, delay);
};
}
searchHandle.addEventListener('input', debounce(function () {
console.log(this.value);
}, 600)
);
</script>
很显然在指定的时间内只允许最后一次查询,这样就大大减少了服务器查询压力
- 监听滚动条事件
[图片上传失败...(image-953c7a-1685071573959)]
function debounce(fn, wait) {
var timeout = null;
return function () {
if (timeout !== null) clearTimeout(timeout);
timeout = setTimeout(fn, wait);
};
}
function handle() {
console.log(Math.random());
}
window.addEventListener("scroll", debounce(handle, 1000));
和上面的表单搜索查询原理一样,都是监听操作事件,在规定的时间内只允许函数触发最后一次
一、节流(throttle)
概念
当持续触发事件时,保证在一定时间内只调用一次事件处理函数;
也就是说:一直触发函数,且每次触发小于给定值,函数节流会每隔这个时间调用一次
防抖与节流的区别
防抖是将多次执行变为最后一次执行,节流是将多次执行变为每隔一段时间执行
应用场景
- 懒加载要监听计算滚动条的位置,使用节流按一定时间的频率获取。
- 计算鼠标移动的距离
- DOM 元素的拖拽功能
- 搜索查询等
实现原理
主要有两种方法:时间戳和定时器
设定一个定时器,调用函数,如果调用函数在给定的一段时间内,那就每隔给定的时间段内执行一次函数
代码示例
- 表单搜索查询
[图片上传失败...(image-7196ff-1685071573959)]
const search = document.getElementById("search");
function input(val) {
console.log(val);
}
function throttle(fun, delay) {
let last, timer;
return function (args) {
const that = this;
const now = +new Date();
/* 以delay为基准,对比上一次(last)的操作时间和当前时间是否在上次操作(last)和delay时间范围内;
如果在范围内,那就清除上次定时器函数操作,开始一个新的定时器函数操作,往复循环
*/
if (last && now < last + delay) {
clearTimeout(timer);
timer = setTimeout(function () {
fun.call(that, args);
}, delay);
} else {
last = now;
fun.call(that, args);
}
};
}
const throttleInput = throttle(input, 1000);
search.addEventListener("input", function (e) {
throttleInput(e.target.value);
});
可以看到在一直输入的情况下每隔一段时间会触发一次函数
- 监听滚动条事件
[图片上传失败...(image-2cc333-1685071573959)]
function throttle (func, delay) {
var timer = null;
var startTime = Date.now();
return function () {
let curTime = Date.now();
let remaining = delay - (curTime - startTime); //剩余时间
let _this = this;
clearTimeout(timer);
if (remaining <= 0) {
// 第一次触发立即执行
func.apply(_this, arguments);
startTime = Date.now();
} else {
timer = setTimeout(func, remaining); //取消当前计数器并计算新的remaining
}
};
};
function handle() {
console.log(Math.random());
}
window.addEventListener("scroll", throttle(handle, 1000));
总结
- 防抖和节流都是为了解决频繁触发某个事件的情况造成的性能消耗。
- 防抖就是在触发后的一段时间内执行最后一次,如:在进行搜索的时候,当用户停止输入后调用方法,节约请求资源
- 节流就是在频繁触发某个事件,每隔一段时间请求一次,如:打游戏的时候长按某个按键,动作是有规律的在间隔时间触发一次
网友评论