当前位置:网站首页>JS封装防抖(代码持续优化)

JS封装防抖(代码持续优化)

2022-08-09 11:25:00 ik i5

1 .认识防抖debounce函数

  • 防抖的过程
    • 当事件触发时,相应的函数并不会立即触发,而是会等待一定的时间;
    • 当事件密集触发时,函数的触发会被频繁的推迟;
    • 只有等待了一段时间也没有事件触发,才会真正的执行响应函数;

在这里插入图片描述

  • 防抖的应用场景
  • 输入框中频繁的输入内容,搜索或 者提交信息;
  • 频繁的点击按钮,触发某个事件;
  • 监听浏览器滚动事件,完成某些特定操作;
  • 用户缩放浏览器的resize事件;

2. 防抖函数的案例

我们都遇到过这样的场景,在某个搜索框中输入自己想要搜索的内容:

  • 比如想要搜索一个MacBook:
    • 当我输入m时,为了更好的用户体验,通常会出现对应的联想内容,这些联想内容通常是保存在服务器的,所以需要一次网络请求;
    • 当继续输入ma时,再次发送网络请求;
    • 那么macbook一共需要发送7次网络请求;
    • 这大大损耗我们整个系统的性能,无论是前端的事件处理,还是对于服务器的压力;
  • 但是我们需要这么多次的网络请求吗?
    • 不需要,正确的做法应该是在合适的情况下再发送网络请求;
    • 比如如果用户快速的输入一个macbook,那么只是发送一次网络请求;
    • 比如如果用户是输入一个m想了一会儿,这个时候m确实应该发送一次网络请求;
    • 也就是我们应该监听用户在某个时间,比如500ms内,没有再次触发时间时,再发送网络请求;

这就是防抖的操作:只有在某个时间内,没有再次触发某个函数时,才真正的调用这个函数;

游戏理解: 防抖就回城
生活理解: 坐电梯

在这里插入图片描述

3.利用 第三方库来实现防抖

	<!-- //第三方库使用防抖节流 -->
	<input type="text">
	<script src="https://cdn.jsdelivr.net/npm/[email protected]/underscore-umd-min.js"></script>
	<script>
		const inputEl = document.querySelector('input')
		let count = 0
		const inputChange = function (event) {
    
			count++
			console.log(`发送了我们的第${
      count}次网络请求`, this,event);
		}
		// 防抖只执行一次
		inputEl.oninput=_.debounce(inputChange,2000)

4. 手写防抖

4. 1防抖基本功能的实现

<!-- //第三方库使用防抖节流 -->
	<input type="text">
	<!-- <script src="https://cdn.jsdelivr.net/npm/[email protected]/underscore-umd-min.js"></script> -->
	<script>
		const inputEl = document.querySelector('input')
		let count = 0
		const inputChange = function () {
    
			count++
			console.log(`发送了我们的第${
      count}次网络请求`);
		}
		// 防抖只执行一次
		inputEl.oninput = debounce(inputChange, 2000)

		// 1 防抖的过程需要传递两个值一个是函数fn另一个是时间
		function debounce(fn, times) {
    
			// 定义一个定时器来来记录上一次的定时器函数的状态
			let timer = null
			// 2 在接受这两个值时需要返回一个函数
			const _debounce = function () {
    
				// 3 在处理防抖时 需要只执行一次 这里需要一个计时器
				// 4 计时器有一个返回的id属性值 ,利用返回的id,让函数只执行最后一次
				// 5 如果有这个id 则停止计时器
				if (timer) clearInterval(timer)   //取消上一次定时器
				timer = setTimeout(() => {
        //延迟执行
					fn()         //外部传入的函数
				}, times)
			}
			return _debounce
		}
	</script>

优化

// 防抖的关键在于定时器的开始与清零
		function debounce(callback,delaytime){
    
			// 定义计时器
			let timer=null
			return function(){
    
				//如果定时器不是null 则需要重新计时
				if (timer!=null) {
    
					clearTimeout(timer)
					
				}
				//如果定时器还是空 ,则开始倒计时
				timer=setTimeout(()=>{
    
					callback&&callback()
				}, delaytime)

			}
		}

4. 2优化参数和this指向

注意上面的this指向为window 参数传递为undefined

<input type="text">
	<!-- <script src="https://cdn.jsdelivr.net/npm/[email protected]/underscore-umd-min.js"></script> -->
	<script>
		const inputEl = document.querySelector('input')
		let count = 0
		const inputChange = function (event) {
    
			count++
			console.log(`发送了我们的第${
      count}次网络请求`, this,event); //这里的this指向window ,event传递的参数指向undefined 
			                                                           //因此需要重新绑定this
		}
		// 防抖只执行一次
		inputEl.oninput = debounce(inputChange, 2000)
		// 1 防抖的过程需要传递两个值一个是函数fn另一个是时间
		function debounce(fn, times) {
    
			// 定义一个定时器来来记录上一次的定时器函数的状态
			let timer = null
			// 2 在接受这两个值时需要返回一个函数 (真正需要执行的函数)
			const _debounce = function (...args) {
       //这里处理args传递的参数
				// 3 在处理防抖时 需要只执行一次 这里需要一个计时器
				// 4 计时器有一个返回的id属性值 ,利用返回的id,让函数只执行最后一次
				// 5 如果有这个id 则取消上一次计时器
				if (timer) clearInterval(timer)   //取消上一次定时器
				timer = setTimeout(() => {
        //延迟执行
					fn.apply(this,args)         //外部传入的函数 
					 //在这里重新绑定this(不绑定this指向的是windows =>这里改变this重新指向调用者input)

				}, times)
			}
			return _debounce      
			// 问题: 主函数需要先执行 ,只不过返回的是undefined
			//undefined 游览器自己处理不做判断
		}
	</script>

4. 3 优化立即执行效果(第一次立即执行)

<!-- 题注 当用户输入一次时, 先执行一次 =>产生联想 -->
	<!-- //第三方库使用防抖节流 -->
	<input type="text">
	<script>
		const inputEl = document.querySelector('input')
		let count = 0
		const inputChange = function (event) {
    
			count++
			console.log(`发送了我们的第${
      count}次网络请求`, this, event); //这里的this指向window ,event传递的参数指向undefined 
			//因此需要重新绑定this
		}
		// 防抖只执行一次
		inputEl.oninput = debounce(inputChange, 2000,true)  //这里可以传入第三个参数

		// 1 防抖的过程需要传递两个值一个是函数fn另一个是时间 
		function debounce(fn, times, imediate=false) {
         				//immediate是否立即执行,默认情况下是不需要立即执行的传入false 
			
			let timer = null
			// 定义全局判断上一次是否是立即执行
			let isVoke=false
			
			const _debounce = function (...args) {
       
			
				if (timer) clearInterval(timer)   //取消上一次定时器

				 //判断是否需要立即执行
				 if (imediate &&!isVoke) {
         //!isVoke=true
				    	fn.apply(this,args)
					      // imediate=false //立即执行完成之后改成false 分析问题 当下一次重新输入时 不会立即执行=>延迟执行
								isVoke=true                          //这里赋值为true 当上一次执行完毕后赋值为true //让其延迟执行
				 }else{
    
					//延迟执行
					 timer = setTimeout(() => {
        //延迟执行
						 fn.apply(this, args)         //外部传入的函数 
            isVoke=false        //abcd=> 当abcd执行完后重启false 在判断是否立即执行
					 }, times)
				 }
			
			}
			return _debounce
		}
  • 后期优化返回值 , 以及取消功能
原网站

版权声明
本文为[ik i5]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_46104934/article/details/126238291