js节流防抖

什么是节流防抖?在学习这个问题前,我们先抛出问题:

假设我现在有这么一个需求:根据input框输入内容打印到控制台

这个问题简单啊,很简单的功能嘛,代码如下:

<body>
	<input type="text" id="input">
	<script>
		let input = document.getElementById('input')
		input.addEventListener('keyup',function(){
			console.log(input.value)
		})
	</script>
</body>

没错,这样确实实现了对输入框进行监听,但是。。。。这个触发事件的频率太频繁了吧,仅仅输入6个汉字,居然触发了这么多次keyup事件,并且我希望打印出的也只是当我停止或暂停输入内容时,所打印的内容。
在这里插入图片描述
上述代码仅仅是用于打印输入框的值,如果我需要根据输入框的值向后台发送ajax请求呢,这么频繁的发送请求,那得多发送多少次请求啊,那有没有什么办法,可以指定当我停止输入超过1s后再打印log或者是发送ajax请求呢?
那就要用到setTimeout定时器了,我们给定时器一个延迟,只有停止输入1s后才触发某种逻辑,代码如下

<body>
	<input type="text" id="input">
	<script>
		let input = document.getElementById('input')
		// 定义一个定时器对象,setTimeout()返回的是一个定时器的id
		let timerId = null
		// 给input输入框绑定Keyup键盘松开事件
		input.addEventListener('keyup',function(){
			// 首先对timerId进行判断,如果已经存在有该定时器逻辑,那么清除这个定时器
			if(timerId){
				clearTimeout(timerId)	// 根据timerId清除对应定时器
			}
			timerId = setTimeout(function(){
				console.log(input.value)	//打印value
				// 执行完定时器逻辑后把定时器置空
				timerId = null
			},1000)
		})
	</script>
</body>

此时结果如下:
在这里插入图片描述
只有当你超过1000ms时,才会去执行定时器中的逻辑,同时因为我们有对定时器做清除,所以即便停止输入超过1s,当我们再次输入停止时,依旧可以出发当前定时器。
在触发事件时,我们并不立即执行逻辑,而是给出一个预定值,只有当预定值到来我们才执行逻辑,我们称之为防抖。但是上面的代码,没有经过封装,还无法做到重复使用,下面我们进行一次封装,代码如下:

	function debounce(fn,delay=500){
		let timerId = null
		// 这里就用到了闭包
		return function (){
			if(timerId){
				clearTimeout(timerId)
			}
			timerId = setTimeout(()=>{
			// 这里主要是为了解决传入函数中this指向的问题,并且传入函数可能还会携带参数
				fn.apply(this,arguments)
				timerId = null
			},delay)
		}
	}
	// 调用时
	input.addEvent('keyup',debounce(function(){
		console.log(input.value)
	},1000))
	// 如果又有input2输入框
	input2.addEventListener('keyup',debounce(function (){
		console.log(input2.value)
	}))

节流:

回顾上面的防抖:它是在指定延时时间之后才执行一次函数

假设现在给某个div元素注册drag拖拽事件,打印当前元素的位置坐标。

  • 如果按照防抖的思想,只有在停止拖拽的时候才打印一次位置

但是我想要在可以拖拽的同时每隔100ms打印一次位置呢

<html>
	<head>
		<style>
			#div1{
				width:200px;
				height:200px;
				border:1px solid #333
			}
		</style>
	</head>
	<body>
		<div id="div1" draggable="true">可拖拽</div>
		<script>
			let div1 = document.getElementById('div1')
			let timerId = null
			div1.addEventListener('drag',function(e){
				if(timerId){
				// 拖拽事件一直不间断被触发,定时器任务是延迟100ms执行的,100ms一到,执行定时器逻辑,打印位置,在这个过程中,timerId有值,拖拽事件虽然一直被触发,但是不做任何操作,只有当timerId为null时,才会去创建一个新的定时器打印位置
					return
				}
				timerId = setTimeout(function (e){
					console.log(e.offsetX,offsetY)
					timerId = null
				},100)
			})
		</script>
	</body>
</html>

下面依旧是封装一个throttle节流函数

	function throttle(fn,delay=500){
		let timerId = null
		return function(){
			if(timerId){
				return
			}
			timerId = setTimeout(()=>{
				fn.apply(this,arguments)
				timerId = null	// 清除定时器任务
			},delay)
		}
	}
	div1.addEventListener('drag',throttle(function (e){
		console.log(e.offsetX,e.offsetY)
	}))

这里有个坑需要注意,定时器那行要使用箭头函数,否则会报错,是因为this的指向问题,定时器中的this指向window,所以定时器中使用箭头函数比较好,但是箭头函数有兼容性问题,需要注意

这里仅作为我自己的记录,水平有限
参考:js节流和防抖问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值