前端——节流、防抖(通俗易懂)

浏览器的scroll(滚动条滚动)、keypress(按动按键)、mousemove(鼠标移动)等等事件在出发时,都是会不断的调用绑定在事件上的回调函数高频触发,如果回调函数复杂就会导致响应跟不上触发,有可能会造成页面的卡顿,极大地浪费资源,降低前端的性能。

对此有两种解决方案:防抖(debounce )节流(throttling )

一、 防抖(debounce )

作用:是在短时间内多次触发事件的回调函数,只执行最后一次,或者只在最开始时执行。

以用户拖拽改变窗口大小,触发resize事件为例,在这过程中窗口的大小一致在改变,所以如果我们在resize事件中绑定回调函数,这个函数将会在拖拽的过程一直触发,如果回调函数过于复杂难免不会造成页面卡顿,而且这种情况在多数情况下也是无意义的,还会造成资源的大量浪费。

普通方案:
			window.addEventListener('resize',()=>{
    
    
				console.log('触发事件');
			});
优化方案
			function debounce(fn,delay){
    
    
				// 维护一个 timer
				let timer=null;
				return function(){
    
    
					// 获取函数的作用域和变量
					let context=this;
					let args=arguments;
					clearTimeout(timer);
					timer=setTimeout(function(){
    
    
						fn.apply(context,args);
					},delay);
				}
			}
			function res(){
    
    
				console.log('触发事件');
			}
			//在 debounce 包装要触发的函数,过1000秒触发;
			window.addEventListener('resize',debounce(res,1000));
代码逻辑:
  • 在resize事件上绑定处理函数,这时debounce函数会立即调用,实际上绑定的函数时debounce函数内部返回的函数。
  • 每一次事件被触发,都会清除当前的timer定时器然后重新设置,到时间调用。
  • 只有在最后一次触发resize事件,才能在delay时间后执行。
添加参数,设置为立即执行函数
			function debounce(fn,delay,rightAway=false){
    
      //rightAway 不传时 ,默认为非立即执行函数
				// 维护一个 timer
				let timer=null;
				return function(){
    
    
					// 获取函数的作用域和变量
					let context=this;
					let args=arguments;
					if(timer) clearTimeout(timer);
					if(rightAway){
    
    
						var now=!timer;
						timer=setTimeout(()=>{
    
    
							timer=null;
						},delay);
						if(now){
    
    
							fn.apply(context,args);
						}
					}else{
    
    
						timer=setTimeout(()=>{
    
    
							fn.apply(context.args);
						},delay);
					}
				}
			}

二、节流(throttling )

作用:类似于防抖,不过节流是在一段时间之内只允许该函数执行一次

定时器实现
			function throttle(fn,delay){
    
    
				var timer =null;
				return function(){
    
    
					let context=this;
					let args=arguments;
					if(!timer){
    
    
						timer=setTimeout(()=>{
    
    
							fn.apply(context,args);
							timer=null;
						},delay);
					}
				};
			}
			function res(){
    
    
				console.log('触发事件');
			}
			window.addEventListener('resize',throttle(res,2000));
时间戳实现
			function throttle(fn,delay){
    
    
				var p =Date.now();
				return function(){
    
    
					let context=this;
					let args=arguments;
					let n=Date.now();
					if(n-p>=delay){
    
    
						fn.apply(context,args);
						p =Date.now();
					}
				};
			}
			function res(){
    
    
				console.log('触发事件');
			}
			window.addEventListener('resize',throttle(res,2000));

以上两重情况都是用于高频触发事件,根据不同场景选择合适的用法。对于有停顿的高频触发事件建议选择防抖,然而对于高频触发并且连续的事件,选择节流。

猜你喜欢

转载自blog.csdn.net/weixin_44716659/article/details/115356350