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


    1 .认识防抖debounce函数

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

    在这里插入图片描述

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

    2. 防抖函数的案例

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

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

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

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

    在这里插入图片描述

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

    	<!-- //第三方库使用防抖节流 -->
    	<input type="text">
    	<script src="https://cdn.jsdelivr.net/npm/underscore@1.13.1/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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    4. 手写防抖

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

    <!-- //第三方库使用防抖节流 -->
    	<input type="text">
    	<!-- <script src="https://cdn.jsdelivr.net/npm/underscore@1.13.1/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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    优化

    // 防抖的关键在于定时器的开始与清零
    		function debounce(callback,delaytime){
    			// 定义计时器
    			let timer=null
    			return function(){
    				//如果定时器不是null 则需要重新计时
    				if (timer!=null) {
    					clearTimeout(timer)
    					
    				}
    				//如果定时器还是空 ,则开始倒计时
    				timer=setTimeout(()=>{
    					callback&&callback()
    				}, delaytime)
    
    			}
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    4. 2优化参数和this指向

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

    <input type="text">
    	<!-- <script src="https://cdn.jsdelivr.net/npm/underscore@1.13.1/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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    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
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 后期优化返回值 , 以及取消功能
  • 相关阅读:
    【C&C++编码规范】
    安装Anaconda与pytorch,在IDEA中配置环境进行编程
    程序波的躺平之道:【1】遁入此门
    数据挖掘-数据的预处理(三)
    002-JAVA的数据类型,变量声明与定义
    jQuery通过调用webservice返回json数据的问题
    前端练习项目(附带页面psd图片及react源代码)
    【IC设计】ZC706板卡点灯入门(含Verilog代码,xdc约束,实验截图)
    广州华锐互动VRAR:VR教学楼地震模拟体验增强学生防震减灾意识
    【Linux】基础:进程的概念
  • 原文地址:https://blog.csdn.net/weixin_46104934/article/details/126238291