If the processing functions of operations such as window resize, Scroll, and input box content verification are complex, or the page is frequently rerendered, the frequency of events triggered is limited, which increases the burden on the browser and leads to poor user experience. We can use debounce and throttle to reduce the frequency of the trigger without affecting the actual effect.

Eg: Request optimization of the search box. When a search term is entered and a search request is triggered immediately, anti-shaking and throttling can combine multiple requests into a single request

Github note portal, pass by a Star?

First, prepare the following code in the HTML file:

<div id="content" style="height:150px; line-height:150px; text-align:center; color: #fff; background-color:#ccc; font-size:80px;"></div>
<script>
    var num = 1;
    var content = document.getElementById('content');

    function count() {
        content.innerHTML = num++;
    };

    content.onmousemove = count;
</script>

Copy the code

Image stabilization

Debounce, simply to prevent shaking.

When the event is fired continuously, debounce merges the event and does not fire the event. When no event is fired for a certain period of time, the event is actually fired.

Non-immediate execution version

The non-immediate version means that the function is not executed immediately after the event is fired, but is executed n seconds later. If the event is fired within n seconds, the function execution time is recalculated.

const debounce = (func, wait, ... args) = > {
  let timeout;
  return function(){
    const context = this;
    if (timeout) clearTimeout(timeout);
    timeout = setTimeout((a)= >{ func.apply(context, args) },wait); }}Copy the code

Call it like this:

content.onmousemove = debounce(count,1000);
Copy the code

Immediate execution

The immediate execution version means that the function executes immediately after the event is fired, and then does not fire the event for n seconds before the effect of the function continues.

const debounce = (func, wait, ... args) = > {
  let timeout;
  return function(){
    const context = this;
    if (timeout) cleatTimeout(timeout);
    letcallNow = ! timeout; timeout = setTimeout((a)= > {
      timeout = null;
    },wait)
    
    if(callNow) func.apply(context,args)
   }
}
Copy the code

Combining with the version

@param immediate true Indicates that the table is executed immediately. False indicates that the table is not executed immediately. */
function debounce(func,wait,immediate) {
    var timeout;

    return function () {
        var context = this;
        var args = arguments;

        if (timeout) clearTimeout(timeout);
        if (immediate) {
            varcallNow = ! timeout; timeout = setTimeout(function(){
                timeout = null;
            }, wait)
            if (callNow) func.apply(context, args)
        }
        else {
            timeout = setTimeout(function(){ func.apply(context, args) }, wait); }}}Copy the code

The throttle

Throttle, while continuously firing events, ensures that the event is fired once at the stall time.

When events continue to be triggered, you throttle the number of events you are throttling for a certain period of time and actually firing an event at the end of that time.

The time stamp version

During the duration of the event firing, the function is executed immediately and every 1s.

const throttle = (func, wait, ... args) = > {
  let pre = 0;
  return function(){
    const context = this;
    let now = Date.now();
    if (now - pre >= wait){
       func.apply(context, args);
       pre = Date.now(); }}}Copy the code

The timer version

During continuous event firing, the function is executed not immediately, but every 1s, and again after stopping event firing.

const throttle = (func, wait, ... args) = > {
  let timeout;
  return function(){
    const context = this;
    if(! timeout){ timeout = setTimeout((a)= > {
        timeout = null;
        func.apply(context,args);
      },wait)
    }
  }
}
Copy the code

Combining with the version

The difference between the timestamp version and the timer version is that the timestamp version of the function fires at the beginning of the time period, while the timer version of the function fires at the end of the time period.

/** * @desc throttling * @param func * @param wait * @param type 1 table timestamp version, 2 table timer version */
function throttle(func, wait ,type) {
    if(type===1) {var previous = 0;
    }else if(type===2) {var timeout;
    }

    return function() {
        var context = this;
        var args = arguments;
        if(type===1) {var now = Date.now();

            if(now - previous > wait) { func.apply(context, args); previous = now; }}else if(type===2) {if(! timeout) { timeout = setTimeout(function() {
                    timeout = null;
                    func.apply(context, args)
                }, wait)
            }
        }

    }
}
Copy the code

The underscore the source code

/** * underscore = underscore /** * underscore * * @param {function} func callback * @param {number} wait * @param {Boolean} immediate set to true Whether to call the function immediately * @return {function} Returns the client calling function */
_.debounce = function(func, wait, immediate) {
    var timeout, args, context, timestamp, result;

    var later = function() {
      // Now compare to the last timestamp
      var last = _.now() - timestamp;
      // If the current interval is less than the set time and greater than 0, reset the timer
      if (last < wait && last >= 0) {
        timeout = setTimeout(later, wait - last);
      } else {
        // Otherwise it is time to execute the callback function
        timeout = null;
        if(! immediate) { result = func.apply(context, args);if(! timeout) context = args =null; }}};return function() {
      context = this;
      args = arguments;
      // Get the timestamp
      timestamp = _.now();
      // Execute the function immediately if the timer does not exist
      varcallNow = immediate && ! timeout;// Create a timer if it does not exist
      if(! timeout) timeout = setTimeout(later, wait);if (callNow) {
        // If the function needs to be executed immediately, apply it
        result = func.apply(context, args);
        context = args = null;
      }

      return result;
    };
  };
Copy the code
  • Implementation for button click-proof: Once I start a timer, as long as my timer is still in place, no matter how much you click it, the callback function will not execute. Once the timer is over and set to NULL, you can click again.
  • Implementation for the delayed execution function: each call to the anti-jitter function determines the interval between the call and the previous one, and if the interval is less than the required interval, a new timer is created, and the delay of the timer is the set time minus the previous interval. Once the time is up, the corresponding callback function is executed.
/** * underscore underscore / wait * * @param {number} func callback * @param {number} wait * @param {object} options To ignore the call to the starting function, pass {leading: false}. * If you want to ignore the trailing function call, pass {trailing: false} * The two cannot coexist, otherwise the function cannot execute * @return {function} returns the client calling function */
_.throttle = function(func, wait, options) {
    var context, args, result;
    var timeout = null;
    // The previous timestamp
    var previous = 0;
    // If options is not passed, set it to an empty object
    if(! options) options = {};// The timer callback function
    var later = function() {
      // If leading is set, set previous to 0
      // For the first if of the following function
      previous = options.leading === false ? 0 : _.now();
      // Set null to prevent memory leaks and for the following timer judgment
      timeout = null;
      result = func.apply(context, args);
      if(! timeout) context = args =null;
    };
    return function() {
      // Get the current timestamp
      var now = _.now();
      // The first entry to the former must be true
	  // Do not execute the function if needed the first time
	  // Set the last timestamp to current
      // In this way, the value of remaining will be greater than 0
      if(! previous && options.leading ===false) previous = now;
      // Calculate the remaining time
      var remaining = wait - (now - previous);
      context = this;
      args = arguments;
      // If the current call is longer than the last call + wait
      // Or the user manually adjusts the time
 	  // If trailing is set, only this condition is entered
	  // If leading is not set, the condition is entered the first time
	  // One more thing, you might think that if the timer is on, you should not enter the if condition
	  // In fact, it will enter because of the timer delay
	  // This is not the exact time, most likely you set 2 seconds
	  // But it takes 2.2 seconds for it to trigger, at which point it enters the condition
      if (remaining <= 0 || remaining > wait) {
        // Clean up the timer if it exists; otherwise, call the second callback
        if (timeout) {
          clearTimeout(timeout);
          timeout = null;
        }
        previous = now;
        result = func.apply(context, args);
        if(! timeout) context = args =null;
      } else if(! timeout && options.trailing ! = =false) {
        // Determine whether the timer and trailing are set
	    // If not, start a timer
        // And can't set both lead and trailing
        timeout = setTimeout(later, remaining);
      }
      return result;
    };
  };
Copy the code

The article source

  • Functions for damping and throttling
  • JS simple implementation of anti – debounce and throttling – throttle