JS的节流和防抖详解

JS的节流和防抖

函数防抖(debounce)

基本概念:在时间被触发n秒在执行回调,如果在这n秒内又被触发,则重新开始计时。

未加防抖函数的例子

function inputChange(content) {
    console.log("inputContent" + content);
 }
 
let input = document.getElementById("unDebounce");

input.addEventListener("keyup", function (e) {
   inputChange(e.target.value);
});

普通防抖函数的例子

/*
  fun:回调函数
  dealy:延时时间
*/
 function debounce(fun, delay) {
    return function (args) {
      let that = this;
      let _args = args;
      clearTimeout(fun.id);
      fun.id = setTimeout(function () {
        fun.call(that, _args);
      }, delay);
    };
}
 let primaryDebounceInput = document.getElementById("primaryDebounce");
 let primaryDebounceChange = debounce(inputChange, 1000);
 primaryDebounceInput.addEventListener("keyup", function (e) {
    primaryDebounceChange(e.target.value);
 });

从该函数我们不难发现:
1、 在防抖函数中使用了闭包。使得fun会一直存在。从而可以清除之前生成的定时器。
2、这是一个延时的防抖函数。并且会不断的创建销毁定时器。比较消耗资源,并不是最优的防抖函数。

优化后的防抖函数的例子

var uDebounce = (fn, wait) => {
   let timer,
     startTimeStamp = 0;
   let context, args;
   // run函数 wait时间到了进入。
   let run = (timerInterval) => {
     timer = setTimeout(() => {
       console.log('进入定时器')
       // 设定当前时间
       let now = new Date().getTime();
       let interval = now - startTimeStamp;
       // 最后一次点击时间和当前时间不足awit
       if (interval < timerInterval) {
         console.log("debounce reset", timerInterval - interval);
         startTimeStamp = now;
         // 再次生成一个定时器
         run(wait - interval);
       } else {
         fn.apply(context, args);
         clearTimeout(timer);
         timer = null;
       }
     }, timerInterval);
   };

   return function () {
     context = this;
     args = arguments;
     let now = new Date().getTime();
     // 每次触发事件便会设定startTimeStamp的时间
     startTimeStamp = now;
     console.log("重新赋值startTimeStamp:" + startTimeStamp)
     // 初始进入或执行完回调函数可再次进入
     if (!timer) {
       console.log("进入if判断")
       run(wait);
     }
   };
 };

// 从优化后的函数可以看出
1、初始会进入run()函数,在wait期间会不断刷新startTimeStamp的值,延时函数到时间执行时判断,最后一次的startTimeStamp和now是否小于wait,是的话则再次进行,由此执行的防抖不会频繁的创建销毁定时器。但是也在一定程度上创建定时器。

立即执行防抖函数的例子

// 增加前缘触发功能
var debounce = (fn, wait, immediate=false) => {
	let timer, startTimeStamp=0;
	let context, args;
 
	let run = (timerInterval)=>{
		timer= setTimeout(()=>{
			let now = (new Date()).getTime();
			let interval=now-startTimeStamp
			if(interval<timerInterval){
				console.log('debounce reset',timerInterval-interval);
				startTimeStamp=now;
				run(wait-interval);  // reset timer for left time 
			}else{
				if(!immediate){
					fn.apply(context,args);
				}
				clearTimeout(timer);
				timer=null;
			}
			
		},timerInterval);
	}
 
	return function(){
		context=this;
		args=arguments;
		let now = (new Date()).getTime();
		startTimeStamp=now; // set timer start time
 
		if(!timer){
			console.log('debounce set',wait);
			if(immediate) {
				fn.apply(context,args);
			}
			run(wait);    // last timer alreay executed, set a new timer
		}
		
	}
 
}

新增了immediate参数,如果设置为true,那么会立即执行。

函数防抖总结:
1、防抖函数分为延时防抖和立即执行防抖,根据具体需求情况选取。
2、防抖函数可以在一定程度上防止资源浪费,减少不必要的接口请求,从而减轻服务器的压力。
3、防抖函数的实际应用场景:窗口大小改变事件onresize、联想搜索(当input框值改变时触发接口请求)等。

函数节流(throttle)

基本概念: 规定在一个单位时间内,只能触发一次函数,如果这个时间内触发多次函数,那么只有一次函数生效

延时节流函数的例子

var throttling = (fn, wait) => {
	let timer;
	let context, args;
	let run = () => {
		timer=setTimeout(()=>{
			fn.apply(context,args);
			clearTimeout(timer);
			timer=null;
		},wait);
	}
	return function () {
		context=this;
		args=arguments;
		if(!timer){
			console.log("throttle, set");
			run();
		}else{
			console.log("throttle, ignore");
		}
	}
}

立即执行节流函数的例子

/// 增加前缘
var throttling = (fn, wait, immediate) => {
	let timer, timeStamp=0;
	let context, args;
 
	let run = () => {
		timer=setTimeout(()=>{
			if(!immediate){
				fn.apply(context,args);
			}
			clearTimeout(timer);
			timer=null;
		},wait);
	}
 
	return function () {
		context=this;
		args=arguments;
		if(!timer){
			console.log("throttle, set");
			if(immediate){
				fn.apply(context,args);
			}
			run();
		}else{
			console.log("throttle, ignore");
		}
	}
 
}

节流函数总结:
1、在规定时间内只触发一次回调函数。
2、实际应用场景:下拉加载更多、onscrool

你可能感兴趣的:(js,javascript,开发语言,ecmascript)