1、节流和防抖的目的:
都是为了限制函数的执行频次,以优化函数触发频率过高导致的响应速度跟不上触发频率,防止在短时间内频繁触发同一事件而出现延迟,假死或卡顿的现象
2、节流和防抖的区别:
防抖:如果不断在delay之前重新触发,那么定时器会不断重新计时,最终会在最后一次完后才执行
节流:目前有一事件A设置了定时器,那么在delay之前触发,都只会触发一次
3、节流和防抖的详解
(1)、防抖 debounce(设置1分钟只会执行一次,如果1分钟内又多次触发,会从再次触发开始重新计算1分钟时间,然后再执行)
触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间
本质:将多次执行变为最后一次执行(重新执行)
举例:比如我们平时在使用搜索框时,我们一输入内容就会发送对应的网络请求,如果我们后面一直有在输入内容,那么就会一直发送网络请求。正确的做法应该是在我们输入期间不发送网络请求,当我们输入完成后在发送网络请求。
(2)、节流 throttle(设置1分钟只会执行一次,一分钟内,多次触发无效,必须等1分钟后才能触发函数)
高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率
本质:将多次执行变成每隔一段时间执行(不能打断我)
举例:比如我们在玩LOL游戏时,当需要回城时,我们触发回城按钮,进入到回城状态进会有一个等待的时间,如果在这个等待时间内有重复去执行回城按钮,这时回城状态并不会做出其他响应,而是等时间到了后才会完成回城。这也说明了,在我们回城的过程中,一直触发回城按钮都是不会响应的,他会按照自己的一个回城时间才做出响应。
4、代码实现简单防抖与节流
4.1、防抖
(1)、简单版
<body>
<!-- 防抖函数 debounce -->
<input type="text" name="" id="" />
<script>
var int = document.querySelector("input");
function inputChange() {
console.log(this.value);
}
// 不加防抖函数,不断的输出
//int.addEventListener("keyup", inputChange);
//加入防抖函数,1秒钟输出一次
var intVal = debounce(inputChange, 1000);
int.addEventListener("keyup", intVal);
//防抖函数
function debounce(fn, delay) {
// 1、定义一个定时器,保存上一次的定时器
var timer = null;
// 2、真正执行的函数
var _debounce = function () {
//3、 取消上一次的定时器
if (timer) clearTimeout(timer);
//4、 保存this
var _this = this;
//5、 延迟执行
timer = setTimeout(function () {
//6、 让fn执行时,指向input
fn.call(_this);
}, delay);
};
return _debounce;
}
</script>
</body>
(2)、this和参数实现
<input type="text" name="" id="" />
<script>
var int = document.querySelector("input");
// 需求:输出输入的内容
function inputChange() {
console.log(this.value);
}
// 不加防抖函数,不停的搜索
// int.addEventListener("keyup", inputChange);
// 加入防抖函数
int.addEventListener("keyup", debounce(inputChange, 1000));
// 防抖函数二:this和参数实现
function debounce(fn, delay) {
//console.log(this, "debounce"); //这里的this指向的是window
// 1、定义一个定时器,保存上一次的定时器
var timer = null;
// 2、真正执行的函数,传入参数
return function (...ages) {
//3、保存this,此时的this指向的是input
var _this = this;
// 4、判断定时器是否存在,清楚定时器
if (timer) clearTimeout(timer);
// 重新调用setTimerout
timer = setTimeout(function () {
//console.log(this);//定时器里的this指向widow
// fn()直接执行,this指向window
fn.apply(_this, ages);
timer = null;
}, delay);
};
}
</script>
(3)、立即执行
<input type="text" name="" id="" value="你好" />
<script>
var int = document.querySelector("input");
// 需求:输出输入的内容
function inputChange() {
console.log(this.value);
}
// 不加防抖函数,不停的搜索
// int.addEventListener("keyup", inputChange);
// 加入防抖函数
int.addEventListener("keyup", debounce(inputChange, 1000, true));
// int.addEventListener("keyup", debounce(inputChange, 1000, false));
// 防抖函数三:立即执行
//创建一个防抖函数debounce
function debounce(fn, delay, immediate = false) {
// 1.定义一个定时器, 保存上一次的定时器
let timer = null;
let isInvoke = false;
// 2.真正执行的函数
const _debounce = function (...ages) {
// 取消上一次的定时器
if (timer) clearTimeout(timer);
// 判断是否需要立即执行
if (immediate && !isInvoke) {
fn.apply(this, ages);
isInvoke = true;
} else {
// 延迟执行
timer = setTimeout(() => {
// 外部传入的真正要执行的函数
fn.apply(this, ages);
isInvoke = false;
}, delay);
}
};
return _debounce;
}
</script>
4.2
(1)、时间戳版
<body>
<!-- 需求:在快速点击的过程中,降低日志打印的频率,1s中执行一次 -->
<button>点我试试</button>
<script>
var btn = document.querySelector("button");
var fn = function () {
console.log("发送请求");
};
// 问题:快速点击按钮,只要点了一次,日志就打印一次
// btn.addEventListener("click", fn);
// 添加节流函数,在2s内,多次点击,只执行一次
btn.addEventListener("click", throttle(fn, 2000));
//参数: fn 真正执行的函数,interval 多久执行一次
function throttle(fn, interval) {
// 1、记录上一次的开始时间
var lastTime = 0;
// 2、事件触发时,真正执行的函数
var _throttle = function () {
// 2.1获取当前事件触发时的时间
var nowTime = new Date().getTime();
// 2.2使用规定好的时间间隔减去当前时间和上一次触发时间的时间间隔,得到多少时间再次触发
var remainTime = interval - (nowTime - lastTime);
if (remainTime <= 0) {
// 2.3触发真正函数
fn();
// 2.4 保留上次触发的时间
lastTime = nowTime;
}
};
return _throttle;
}
</script>
(2)、定时器版
<body>
<!-- 需求:在快速点击的过程中,降低日志打印的频率,2s中执行一次 -->
<button>点我试试</button>
<script>
var btn = document.querySelector("button");
var fn = function () {
console.log("发送请求");
};
// 问题:快速点击按钮,只要点了一次,日志就打印一次
// btn.addEventListener("click", fn);
// 添加节流函数,在2s内,多次点击,只执行一次
btn.addEventListener("click", throttle(fn, 2000));
//参数: fn 真正执行的函数,interval 多久执行一次
// 定时器方式
function throttle(fn, delay) {
//1、设置标志,判断函数是否执行
var sign = true;
return function () {
//2、 在函数开头判断标志是否为 true,不为 true 则中断函数
if (!sign) return;
//3、 sign 设置为 false,防止执行之前再被执行
sign = false;
//4、 保存this
var _this = this;
//5、 延迟执行函数,delay 时间后执行
setTimeout(function () {
fn.call(_this);
sign = true;
}, delay);
};
}
</script>
</body>
5、节流的应用场景
防抖
表单元素的校验,如手机号,邮箱,用户名等,部分搜索功能的模糊查询结果实现
搜索框搜素输入
文本编辑器实时保存
节流
高频事件,例如快速点击、鼠标滑动、resize事件、scroll事件
下拉加载
视频播放记录时间等
1153

被折叠的 条评论
为什么被折叠?



