Anti-shake and throttling

Anti-shake and throttling is an important means of performance optimization in JS. For high-frequency triggered listening events such as onresize, OnScroll, onINPUT and so on, if the callback is a function that occupies a large amount of resources, it will cause a series of problems such as page lag and affect user experience. At this point, you need to use the knowledge of anti-shake and throttling to optimize

Debounce

Anti – shake: if triggered continuously within a certain period of time, cancel the execution of the function and refresh the setting of the time

Here’s a scroll event to illustrate the effect:

Simple code implementation:

 function debounce(fn, delay) {
     let timer = null
 ​
     // Here is a closure that refers to a variable in the debounce scope
     return function(e) {
         const content = this
         // If the timer is not empty, an existing timer is working and you need to clear the timer to reset the time
         if(timer) {
             clearTimeout(timer)
         }
 ​
         // Set a timer to run after delay seconds
         timer = setTimeout(() = > {
             // Handle the this pointing problem and pass in the event object
             fn.apply(content, arguments)
         }, delay)
     }
 }
Copy the code

The above implementation executes the function passed in after the event has stopped executing for a specified period of time, and another implementation executes the function passed in once at the beginning of the event and does not execute it during a continuous firing, called immediately

To implement this immediate function, we need to add a new immediate variable to indicate whether the function is enabled or not. If yes, set the timer to null within the timer. If yes, check whether the current timer is null outside the timer and execute the function passed in. Specific operations are as follows:

 function debounce(fn, delay, immediate) {
     let timer = null
 ​
     return function(e) {
         const context = this
 ​
         if(timer) clearTimeout(timer)
 ​
         if(immediate) {
             // Is "runnable" when timer is null
             letvalid = ! timer timer =setTimeout(() = > {
                 // The timer is set to null when the timer ends
                 timer = null
             }, delay)
 ​
             if(valid) fn.apply(context, arguments)}else {
             timer = setTimeout(() = > {
                 fn.apply(context, arguments)
             }, delay)
         }
     }
 }
Copy the code

Throttle

Throttling: When events continue to fire, functions are executed only after a certain amount of time, similar to skill cooldowns

Again, a scroll event is used to demonstrate throttling:

Simple code implementation:

 function throttle(fn, delay) {
     let valid = true
     const content = this
     
     return function(e) {
         if(! valid)return
         
         // Set valid to false when entering a function, and true when the contents of the timer are executed
         valid = false
         
         setTimeout(() = > {
             // Handle the this pointing problem and pass in the event object
             fn.apply(content, arguments)
             valid = true
         }, delay)
     }
 }
Copy the code

In addition to the timer implementation above, timestamps can also be used for throttling:

 function throttle(fn, delay) {
     // Set a timestamp prev for the last execution
     let prev = 0
     
     return function(e) {
         const context = this
         // Obtain the current timestamp now. If now-prev is greater than delay, the cooling is complete
         const now = +new Date(a)if(now - prev > delay) {
             fn.apply(context, arguments)
             prev = now
         }
     }
 }
Copy the code

The two methods are different. In the case of a timer, it is executed after a delay of seconds and again after the triggering event is stopped. In the case of a timestamp, it is executed at the beginning and is not executed after the triggering event is stopped