防抖节流 补充篇

防抖和节流一直都是 前端面试中比较常问的问题
那究竟是什么是防抖 什么节流呢
首先 我们先来谈谈 防抖吧 举一个小例子 大家都知道 照相机吧 如果拍照的时候 突然抖动一下 是不是特别影响拍照效果 其实在项目中有类似这样的问题 比较影响用户的体验
防抖: 在事件触发之后 在特定的时间内 只能执行一次 如果再次触发 时间将会重新计时
比如是 2s 的时间 在 1.5s重新触发下 那么将重新计算2s的时间 执行事件
我们用一个实际的小例子 来说:
在页面上创建一个div 高200px 铺满屏幕的宽度

div{
	width: 100%;
	height: 200px;
	background-color: #999;
	text-align: center;
	font-size: 50px;
	line-height: 200px;
}
<div id="d1">0</div>
let num=0;
function add(){
	div.innerHTML=num++;
}
d1.onmousemove=add;

在这里插入图片描述
我们给div绑定了一个事件 只要 鼠标在上面移动 就会让上面数字 +1
如果不加和节流的话 只要我们在上面移动 数字就会出现疯狂的+1 甚至快的我们都看不见 加的数字
因为 只要鼠标哪怕是轻微动一下 就会触发一下 可以想象一下 这样 显然 给用户的体验不是太好
这个时候 就可以用到我们的防抖了 设置每次 +1的 时间间隔 2s 若鼠标滑动 那么将重新计时 每次用户鼠标停下来 它才会 +1 要不只要用户在移动鼠标 他就不会 +1
不过这样的情况也分为俩种:
1.一种是 事件触发后俩秒执行

function fangdou1(func,wait){
	let timeout; 
	return function(){
		if(timeout) clearTimeout(timeout);
		timeout=setTimeout(function(){
			func.apply(this);  //  保证内外 this 指向一直 func 是 windw对象下的自定义函数
		},wait)
	}
}
d1.onmousemove=fangdou1(add,2000); // 传入要执行的操作的自定义函数  第二个参数时间间隔

2.另一种是 触发事件后 立即执行 等待俩秒后再执行 下一次操作

function fangdou2(func,wait){
	let timeout=false;
	return function(){
		if(timeout) clearTimeout(timeout);
		let canMove=!timeout;   // 类型转换
		timeout=setTimeout(function(){
			timeout=false;
		},wait)
		if(canMove) func.call(this);
	}
}
d1.onmousemove=fangdou2(add,2000); // 传入要执行的操作的自定义函数  第二个参数时间间隔
第一种情况比较常见 第二种情况 也有需要 但比较少 
我们先定义一个开关  canMove
只要 canMove 是 true  他才执行函数  
 但这个时候注意 canMove=!timeout 只要当timeout=false 的时候
canMove 才为true  
这个时候给大家复习个知识点  
一个定时器对象 的布尔类型是true 即使 被清除了定时器他也是true
也就是说 只要一个对象被赋值成布尔对象 就是true:  var a=setTimeout(()=>{},1000)  
console.log(a==true)  // 打印出 true
clearTimeOut(a)  console.log(a==true)  // 打印出来还是true
第一次 他会立即执行 因为 timeout的初值是 false
如果第二次再让它 +1  这个时候 timeout=true  被赋值了定时器对象了 那么canMove=!timeout  canMove=false
这个时候 只要定时器里面的  timeout=false 没有执行的话  那么 canMove 就不可能等于 true
需要 用户 鼠标一动 他就会立即+1  但是下次 必须再等俩秒之后 再动 才会+1 

上面的俩种情况根据具体情况我们进行取舍
3.好了 我们下面讲讲 节流的作用
其实 听到这个名字我想到的就是 节省流量 不知道 你们是不是呢
其实在真实的情况下 也确实有节省流量的作用 比如 在网速不好的情况下 用户不停的点击往后台发送请求
这里 节流 也有俩种情况 首先我们先来了解下 节流的概念
节流: 在连续发生的事件中,在特定的时间内只能执行一次
听了概念之后是不是和防抖很像 但不同的是 节流是连续触发事件 时间并不会重新计算
3.1 使用定时器 做节流
不管用户怎么动鼠标 始终是俩秒内执行一次 +1 当用户暂停的时候 也将会暂停+1
相当于 定义一个开关 timeout=false
第一次 (!timeout)=true 的时候设置定时器 timeout=setTimeout执行程序 此时timeout=true
等俩秒后 将 timeout改为false的时候才执行下次 +1

function jieliu1(func,wait){
	let timeout=false;
	return function(){
		if(!timeout){
			timeout=setTimeout(function(){
				timeout=false;
				func.call(this);
			},wait)
		}
	}
}
d1.onmousemove=jieliu1(add,2000); // 传入要执行的操作的自定义函数  第二个参数时间间隔

3.2,上面的程序 在web页面还行 在 移动端效果可能不太好 在移动端 我们可以采用 时间戳的方法进行设置节流
利用俩次时间戳的差值为两秒 执行一次程序 设置 pre 初始值为0 第一次触发事件 是肯定执行的
执行完之后 将 获取到的时间戳 赋值给pre 那么下一次 获取到时间戳 next-pre>2000的时候才会执行程序
这种效果更好

function jieliu2(func,wait){
	let pre=0;
	return function(){
		let next=Date.now();
		console.log(next,pre);
		if((next-pre)>=wait){
			func.call(this);
			pre=next;
		}
	}
}
d1.onmousemove=jieliu2(add,2000); // 传入要执行的操作的自定义函数  第二个参数时间间隔

上面运用到了 闭包得知识 封装的 防抖节流事件 希望能给大家带来帮助 如果觉得有用的话点个赞
上面 call apply 和 bind 更改 this 当前作用域 不太了解的童鞋 可以看我之前的博客
https://blog.csdn.net/yunchong_zhao/article/details/104439466

发布了196 篇原创文章 · 获赞 66 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/yunchong_zhao/article/details/104597753