节流
定义
高频事件触发,但在n秒内只会执行一次,所以节流会西施函数的执行频率
应用场景
举例:预定一个函数只有在大于等于执行周期时才执行,周期内调用不执行。就好像你在淘宝抢购某一件限量热卖商品时,你不断点刷新点购买,可是总有一段时间你点上是没有效果,这里就用到了节流,就是怕点的太快导致系统出现bug。
应用场景:多数在监听页面元素滚动事件的时候用到,因为滚动事件,是一个高频触发的事件,以下是监听页面元素滚动的式例代码
代码实现
// 函数节流
var canRun = true;
document.getElementById("throttle").onscroll = function(){
if(!canRun){
// 判断是否已空闲,如果在执行中,则直接return
return;
}
canRun = false;
setTimeout(function(){
console.log("函数节流");
canRun = true;
}, 300);
};
逻辑
节流的要点:声明一个变量当标识位,记录当前代码是否在执行
如果空闲,则可以正常触发方法执行
如果代码正在执行,则取消这次执行方法,直接return。
这个方法的作用是监听ID为throttle元素的滚动事件
当canRun为true,则代表现在的滚动处理时间是空闲的,可以使用
通过关卡if(!canRun),等于就拿到了通行证。然后下一步的操作就是立马将关卡关上canRun=false。这样,其他请求执行滚动事件的方法,就被挡回去了。
接着用setTimeout规定最小的时间间隔300,接着再执行setTimeout方法体里面的内容。
最后,等setTimeout里面的方法都执行完毕,才释放关卡canRun=true,允许下一个访问者进来。
这个函数节流的实现形式,需要注意的是执行的间隔时间是>=300ms。如果具体执行的方法是包含callback的,也可以将canRun=true这一步放到callback中。理解了函数节流的关卡设置重点,其实改起来就简单多了。
防抖
定义
触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间
应用场景
举例:就好像在百度搜索时,每次输入之后都有联想词弹出,这个控制联想词的方法就不可能是输入框内容一改变就触发的,他一定是当你结束输入一段时间之后才会触发。
函数防抖的应用场景,最常见的就是用户注册时候的手机号码验证和邮箱验证了。只有等用户输入完毕后,前端才需要检查格式是否正确,如果不正确,再弹出提示语。以下还是以页面元素滚动监听的例子,来进行解析:
代码实现
// 函数防抖
var timer = false;
document.getElementById("debounce").onscroll = function(){
clearTimeout(timer); // 清除未执行的代码,重置回初始化状态
timer = setTimeout(function(){
console.log("函数防抖");
}, 300);
};
逻辑
函数防抖的要点,需要一个setTimeout来辅助实现。延迟执行需要跑的代码。
如果方法多次触发,则把上次记录的延迟执行代码用clearTimeout清掉,重新开始。
如果计时完毕,没有方法进来访问触发,则执行代码。
这个方法的作用是监听ID为debounce元素的滚动事件
进入滚动事件方法体的时候,做的第一件事就是清除上次未执行的setTimeout。而setTimeout的引用id由变量timer记录。
clearTimeout方法,允许传入无效的值。所以这里直接执行clearTimeout即可。
然后,将需要执行的代码放入setTimeout中,再返回setTimeout引用给timer缓存。
如果倒计时300ms以后,还没有新的方法触发滚动事件,则执行setTimeout中的代码。
函数防抖的实现重点,就是巧用setTimeout做缓存池,而且可以轻易地清除待执行的代码。
其实,用队列的方式也可以做到这种效果。这里就不深入了。
区别
防抖动是将多次执行变为最后一次执行,节流是将多次执行变成每隔一段时间执行。
防抖是一段时间内执行一次,如果这段事件内有事件执行,则重新开始计时
节流是一段时间执行一次,这个频率是非常快的,但是节流把这个频率降下来了,每隔一段时间执行一次
可直接运行的代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div class="border">
<div class="content">普通函数</div>
</div>
<div class="border">
<div class="content">防抖</div>
</div>
<div class="border">
<div class="content">节流</div>
</div>
</body>
</html>
<style>
.border {
width: 100px;
height: 100px;
overflow: scroll;
margin-bottom: 30px;
}
.content {
border: 1px solid red;
width: 100px;
height: 300px;
}
</style>
<script>
let normal0 = document.getElementsByClassName('border')[0];
let normal1 = document.getElementsByClassName('border')[1];
let normal2 = document.getElementsByClassName('border')[2];
normal0.onscroll = function () {
console.log('普通函数');
};
//防抖
var timer = null;
normal1.onscroll = function () {
clearTimeout(timer);
timer = setTimeout(() => {
console.log('防抖');
}, 300);
};
//节流
let canScroll = true;
normal2.onscroll = function () {
if (canScroll) {
canScroll = false;
setTimeout(() => {
console.log('节流');
canScroll = true;
}, 300);
}
return;
};
</script>