节流的应用场景
- DOM元素的拖拽功能实现
- 射击游戏
- 计算鼠标移动距离
- 监听scroll滚动事件
要注意的是这里的滚动事件和上一篇的防抖不一样,上一个是停止滚动距离等待事件多少后才能监听,这里是隔一段事件监听一次
节流的概念
上面了解了节流的应用场景后,让我们来了解一下节流的概念
节流: 如果你持续触发事件每隔一段时间,只会执行一次事件;
用什么来形容呢,就好像高铁进站,安检的时候,虽然人一直在走,但是安检员必须有一定的时间对乘客进行检查,才会放行下一个
怎么解决节流
还是上一篇的老例子,我们这里引入,方便大家观看:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.wrapper {
background-color: #444;
height: 200px;
line-height: 200px;
/* 加入margin方便观察效果 */
margin-left: 80px;
width: 30%;
color: #fff;
text-align: center;
}
</style>
</head>
<body>
<div class="wrapper"></div>
</body>
</html>
js准备部分
//获取当前的div
let wrapper = document.querySelector('.wrapper');
// 计数
let count = 0;
// 事件
function dosomeThing(e) {
wrapper.innerHTML = count++;
}
因为上一篇博客已经很详细的讲解了很多细节性的东西,比如改this以及找回event对象,所以这里直接引入两种方法
利用时间戳(进去立即执行一次,出去不执行)
function throttleTime(func, wait) {
// 定义一个变量接受this,参数
let that, argus;
//定义时间为0
let old = 0;
return function() {
// 记录this和event事件
that = this;
argus = arguments
// 定义现在的时间撮
// valueOf() 返回 Date 对象的原始值。等同于getTime(),返回 1970 年 1 月 1 日至今的毫秒数。
let now = new Date().valueOf();
//这里now - old肯定大于wait使得这里的进去立马执行
if (now - old > wait) {
// 立即执行函数
func.apply(that, argus)
// 把新的赋值旧的
old = now;
}
}
}
代码有详细的介绍,这里就不在过多介绍
利用定时器(出去执行一次,进入的时候不立即执行)
function throttleSetTimerOut(func, wait) {
let that, argus, timer;
return function() {
// 保存this,event,
that = this;
argus = arguments;
// 因为上面timer没有赋值所以!timer为true
if (!timer) {
timer = setTimeout(function() {
func.apply(that, argus)
// 为了保证下一次能进去,这里清空
timer = null
}, wait)
}
}
}
Double 进入立即执行,出来再一次执行
function throttleAll(func, wait) {
let timer, that, argus;
let old = 0; //记录旧的时间
return function() {
// 记录this,event
that = this;
argus = arguments;
let now = new Date().valueOf(); //现在的时间
// console.log('外面的时间差', now - old)
// 定时器是异步的
if (now - old > wait) {
// console.log('时间执行')
if (timer) {
// 如果定时器有值,清楚定时器,以便两个同时触发,并赋值null,避免后续进不去下一个if条件最后进不去
clearTimeout(timer);
timer = null;
}
func.apply(that, argus);
old = now;
} else if (!timer) {
// console.log('定时器执行')
timer = setTimeout(function() {
func.apply(that, argus);
old = new Date().valueOf(); //要是能进计时器说明这里应该重新计时,避免两次同时触发
// 同时清空计时器,为了让下一次还能进来
timer = null; //这里有没有都能执行
}, wait)
}
}
}
这边是直接封装好的,可以直接取用,func是执行函数,wait等待时间;