Detailed explanation of throttling and anti shake of JS

Keywords: Javascript ECMAScript

Throttling and anti chattering of JS

Function debounce

Basic concept: the callback is executed within n seconds after the time is triggered. If it is triggered again within n seconds, the timing will be restarted.

Examples without anti shake function

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

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

Examples of common anti shake functions

/*
  fun:Callback function
  dealy:Delay Time 
*/
 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);
 });

From this function, it is not difficult to find:
1. Closures are used in the anti shake function. So that fun will always exist. This clears the previously generated timer.
2. This is a delayed anti shake function. And will continue to create destruction timers. Comparing the consumption of resources is not the optimal anti shake function.

An example of the optimized anti shake function

var uDebounce = (fn, wait) => {
   let timer,
     startTimeStamp = 0;
   let context, args;
   // The wait time of the run function is up.
   let run = (timerInterval) => {
     timer = setTimeout(() => {
       console.log('Enter timer')
       // Set current time
       let now = new Date().getTime();
       let interval = now - startTimeStamp;
       // The last click time and the current time are insufficient awit
       if (interval < timerInterval) {
         console.log("debounce reset", timerInterval - interval);
         startTimeStamp = now;
         // Generate a timer again
         run(wait - interval);
       } else {
         fn.apply(context, args);
         clearTimeout(timer);
         timer = null;
       }
     }, timerInterval);
   };

   return function () {
     context = this;
     args = arguments;
     let now = new Date().getTime();
     // Each time the event is triggered, the startTimeStamp time is set
     startTimeStamp = now;
     console.log("Reassign startTimeStamp: " + startTimeStamp)
     // After the initial entry or execution of the callback function, you can enter again
     if (!timer) {
       console.log("get into if judge")
       run(wait);
     }
   };
 };

//It can be seen from the optimized function
1. Initially, it will enter the run() function. During the wait period, the value of startTimeStamp will be continuously refreshed. When the delay function is executed, it will judge whether the last startTimeStamp and now are less than wait. If yes, it will be carried out again. Therefore, the anti shake will not be frequently created and destroyed. However, timers are also created to some extent.

Example of immediate execution of anti shake function

// Add leading edge trigger function
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
		}
		
	}
 
}

The immediate parameter is added. If it is set to true, it will be executed immediately.

Function anti shake summary:
1. The anti shake function is divided into delay anti shake and immediate anti shake, which is selected according to the specific needs.
2. The anti shake function can prevent resource waste and reduce unnecessary interface requests to a certain extent, so as to reduce the pressure of the server.
3. Practical application scenarios of the anti shake function: window size change event onresize, associative search (interface request is triggered when the input box value changes), etc.

Function throttle

Basic concept: it is specified that a function can only be triggered once in a unit time. If a function is triggered multiple times within this time, only one function will take effect

Example of delay throttling function

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");
		}
	}
}

Example of immediate execution of throttling function

///Increase leading edge
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");
		}
	}
 
}

Summary of throttling function:
1. The callback function is triggered only once within the specified time.
2. Practical application scenario: drop down to load more, onscrool

Posted by rp2006 on Thu, 21 Oct 2021 23:11:20 -0700