防抖与节流

防抖与节流

什么是防抖与节流? 有什么区别?怎么实现?

场景

在滚动事件做一个复杂取值计算或者频繁的触发一个事件,很影响浏览器性能并容易导致页面卡顿,所以要合并多次请求,通过函数做一个精确操作。这是就会用到函数防抖或者节流

防抖

触发高频函数事件后,n秒内函数只能执行一次,如果在n秒内这个事件再次被触发的话,那么会重新计算时间

这是未添加防抖的

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style>
			div#app>div{
				height: 300px;
			}
			div#app>div:nth-child(2n){
				background-color: red;
			}
		</style>
	</head>
	<body>
		<div id="app">
			<div>1</div>
			<div>2</div>
			<div>3</div>
			<div>4</div>
			<div>5</div>
			<div>6</div>
			<div>7</div>
			<div>8</div>
			<div>9</div>
			<div>10</div>
			<div>11</div>
			<div>12</div>
		</div>
		<script>
			function showTop  () {
				var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
			  console.log('滚动条位置:' + scrollTop);
			}
			window.onscroll  = showTop
		</script>
	</body>
</html>

这是做了防抖的

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style>
			div#app>div{
				height: 300px;
			}
			div#app>div:nth-child(2n){
				background-color: red;
			}
		</style>
	</head>
	<body>
		<div id="app">
			<div>1</div>
			<div>2</div>
			<div>3</div>
			<div>4</div>
			<div>5</div>
			<div>6</div>
			<div>7</div>
			<div>8</div>
			<div>9</div>
			<div>10</div>
			<div>11</div>
			<div>12</div>
		</div>
		<script>
		/*****************************简化后的分割线 ******************************/
		/*
		防抖(debounce)
		基于上述场景,首先提出第一种思路:在第一次触发事件时,不立即执行函数,
		而是给出一个期限值比如200ms,然后:
		
		如果在200ms内没有再次触发滚动事件,那么就执行函数
		
		///
		如果在200ms内再次触发滚动事件,那么当前的计时取消,重新开始计时
		///
		效果:如果短时间内大量触发同一事件,只会执行一次函数。
		
		实现:既然前面都提到了计时,那实现的关键就在于setTimeOut这个函数,
		由于还需要一个变量来保存计时,考虑维护全局纯净,可以借助闭包来实现:
		
		

		*/
	   // fn [function] 需要防抖的函数
		// delay [number] 毫秒,防抖期限值
	   
		function debounce(fn,delay){
			let timer = null //借助闭包
			return function() {
				if(timer){
					clearTimeout(timer) 
				}
				timer = setTimeout(fn,delay) // 简化写法
			}
		}
		// 然后是旧代码
		function showTop  () {
			var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
		  console.log('滚动条位置:' + scrollTop);
		}
		
		// window.onscroll = debounce(showTop,1000)
		 // 为了方便观察效果我们取个大点的间断值,实际使用根据需要来配置
		 
			var fn=debounce(showTop,1000)
			
		 window.onscroll = function(){
			 fn();
		 }
		</script>
	</body>
</html>

节流

高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style>
			#btn{
				height: 35px;
				padding: 5px;
				background-color: green;
				color: #fff;
				border: 0px;
				outline: none;
			}
		#btn.dis{
			background-color: #ddd;
			cursor: not-allowed;
		}
		</style>
	</head>
	<body>
		<div id="app">
			<button type="button" id="btn">发送验证码</button>
		</div>
		<script>
			var btn=document.getElementById("btn");
			
			var fn=throttle(getCode,5000);
			let n=5;
			
			btn.onclick=function(){
				fn();
				//getCode();
				this.classList.add("dis");
				this.disabled=true;
				
				let t=setInterval(()=>{
					n--;
					this.innerHTML=n+" 秒后发送新验证码";
					// console.log("n:",n,"this:",this);
					if(n==0){
						clearInterval(t);
						this.classList.remove("dis");
						this.innerHTML="发送验证码";
						this.disabled=false;
					}
				},1000);
			}
			
			function getCode(){
				console.log("向后台请求验证码");
			}

			
			function throttle(fn,delay){
				let valid = true
				return function() {
				   if(!valid){
					   //休息时间 暂不接客
					   return false 
				   }
				   // 工作时间,执行函数并且在间隔期内把状态位设为无效
					valid = false
					setTimeout(() => {
						fn()
						valid = true;
					}, delay)
				}
			}
			/* 请注意,节流函数并不止上面这种实现方案,
			   例如可以完全不借助setTimeout,可以把状态位换成时间戳,然后利用时间戳差值是否大于指定间隔时间来做判定。
			   也可以直接将setTimeout的返回的标记当做判断条件-判断当前定时器是否存在,如果存在表示还在冷却,并且在执行fn之后消除定时器表示激活,原理都一样
				*/

			// // 以下照旧
			// function showTop  () {
			// 	var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
			//   console.log('滚动条位置:' + scrollTop);
			// }
			// window.onscroll = throttle(showTop,1000) 
		</script>
	</body>
</html>

应用场景

debounce

  • search搜索联想,用户在不断输入值时,用防抖来节约请求资源。
  • 频繁操作点赞和取消点赞,因此需要获取最后一次操作结果并发送给服务器

throttle

  • 鼠标不断点击触发,mousedown(单位时间内只触发一次)
  • window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值