在进行窗口的操作或者输入框操作时,如果事件处理函数用的频率无限制,会加重浏览器和服务器的负担,此时我们就可以用防抖(debounce)和节流(throttle)的方式来减少调用频率,同时又不影响实际效果。
一、防抖
概念: 单位时间内,频繁触发一个事件,以最后一次触发为准
(将多次操作合并为一次操作进行)
实现: 声明一个变量存储定时器,每次执行事件时,都会清除上一次的定时器,再开启本次定时器。
模板案例:
function debounce(fun,delay){
let timer=null;
return function(){
if(timer){
clearTimeout(timer)
}
timer=setTimeout(() => {
fun.apply(this,arguments);
}, delay)
}
}
输入框事件案例:
<input type="text" name="" id="inp">
<script>
//声明全局变量存储定时器ID
var timeID = null
// 获取输入框节点
var inp = document.getElementById('inp')
// 输入框输入事件
inp.oninput = function () {
//1.先清除之前的定时器
clearTimeout(timeID)
//2.开启本次定时器
timeID = setTimeout(() => {
console.log(this.value)
}, 500)
}
</script>
二、节流
概念: 单位时间内
,触发一个事件,只会触发一次
(一定时间内只触发一次函数)
1.时间戳实现
实现: 声明变量存储上一次的触发事件,每一次触发获取当前时间,判断当前时间与上一次触发时间是否超过间隔,如果超过则执行事件处理代码,存储本次触发时间。
模板案例:
function throttled(fn,delay){
let lastTime = null;
return function(){
let currentTime = Date.now();
if(newTime - oldTime >= delay){
fn();
lastTime = currentTime;
}
}
点击事件案例:
<button id="btn">点我呀</button>
<script>
//声明一个全局变量存储触发时间
let lastTime = null
// 获取按钮节点
var btn = document.getElementById('btn')
//页面滚动事件
btn.onclick = function () {
//1.每一次触发 先获取本次时间戳
let currentTime = Date.now()
//2.判断当前时间 与 上次触发时间 是否超过间隔
if (currentTime - lastTime >= 3000) {
console.log(this.innerHTML)
//3.存储本次的触发时间
lastTime = currentTime
}
}
</script>
2.定时器实现
实现: 声明一个变量存储定时器,如果定时器还未被清空,则退出,如果定时器被清空,再开启本次定时器。
模板案例:
function throttle(fun,delay){
let timer=null;
return function(){
if(timer){
return ;
}
timer=setTimeout(() => {
fun.apply(this,arguments);
timer=null;
}, delay)
}
}
三、应用场景
防抖在连续的事件,只需触发一次回调的场景有:
- 搜索框搜索输入。只需用户最后一次输入完,再发送请求。
- 窗口大小resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。
- 登录、发短信等按钮避免用户点击太快,以致于发送了多次请求,需要防抖。
节流在间隔一段时间执行一次回调的场景有:
- 滚动加载,加载更多或滚到底部监听
- 搜索框,搜索联想功能
监听滚动事件判断是否到页面底部自动加载更多(可用防抖也可用节流,分情况):
给 scroll 加了 debounce (防抖动函数)后,只有用户停止滚动后,才会判断是否到了页面底部;如果是 throttle(节流函数) 的话,只要页面滚动就会间隔一段时间判断一次