Function anti shake and throttling

cause

Because you need to monitor the mouse wheel when writing the front-end page, which will trigger many functions in a short time, causing the page to jam. I happened to see this when I was looking at GitHub, so I recorded it.

debounce

Function anti shake is to make a function wait for a certain time after the last execution to stop triggering the function and then execute it. If the function is triggered again within the waiting time, the waiting time will be recalculated.

Under core source code

_.debounce = function(func, wait, immediate) {
    // immediate defaults to false
    var timeout, args, context, timestamp, result;
    var later = function() {
      // When the function returned by_.debounce is called multiple times during the time interval specified by wait, the value of timestamp will be constantly updated, resulting in last < wait & & last > = 0 always being true, thus starting a new timer to delay the execution of func
      var last = _.now() - timestamp;
      if (last < wait && last >= 0) {
        timeout = setTimeout(later, wait - last);
      } else {
        timeout = null;
        if (!immediate) {
          result = func.apply(context, args);
          if (!timeout) context = args = null;
        }
      }
    };
    return function() {
      context = this;
      args = arguments;
      timestamp = _.now();
      // When this method is called for the first time and immediate is true, func function is called
      var callNow = immediate && !timeout;
      // If this method is called for the first time within the time interval specified by wait, the start timer will call func function regularly
      if (!timeout) timeout = setTimeout(later, wait);
      if (callNow) {
        result = func.apply(context, args);
        context = args = null;
      }
      return result;
    };
  };

Simplified edition

  var debounce = function ( fn, wait, immdediate) {
    var timer = null,
        pre = 0;
    return function () {
      var context = this;
      var args = arguments;
      var now = +new Date();
      var left = now - pre - wait;
      pre = now;
      // If the last function call has exceeded the expected time, or the timer is not set at this time
      if ( left > 0 ){
        fn.apply(context,args);
        return ;
      }
      //Recalculate the expiration time every time you enter the function
      clearTimeout(timer);
      timer = setTimeout(function () {
        clearTimeout(timer);
        timer = null;
        fn.apply(context,args);
        pre = +new Date();  //Function called and pre updated
      },wait);
    }
  }

throttle

Every time interval to execute a function, to avoid excessive function execution, this way is called function throttling. The biggest difference between throttling and anti jitter is that throttling ensures that it will be executed at least once in a period of time. You can imagine turning the faucet down. It is mainly used in a large number of scenarios where continuous events are triggered quickly and frequently, such as onscroll, onresize.

Under core source code

_.throttle = function(func, wait, options) {
    /* options Default value
     *  Indicates that when the return value method is called for the first time, func will be called immediately; otherwise, only the current time will be recorded, and func will be called when the time interval of the second call exceeds wait.
     *  options.leading = true;
     * Indicates that when a method is called, if the time interval specified by wait is not reached, the start timer will delay the call of func function. If the return value method is called later without reaching the time interval specified by wait and func function and being called, the called request will be discarded.
     *  options.trailing = true; 
     * Note: when options.tracking = false, the effect is the same as the simple implementation above
     */
    var context, args, result;
    var timeout = null;
    var previous = 0;
    if (!options) options = {};
    var later = function() {
      previous = options.leading === false ? 0 : _.now();
      timeout = null;
      result = func.apply(context, args);
      if (!timeout) context = args = null;
    };
    return function() {
      var now = _.now();
      if (!previous && options.leading === false) previous = now;
      // Calculate remaining time
      var remaining = wait - (now - previous);
      context = this;
      args = arguments;
      // When the time interval specified by wait is reached, func function is called
      // Highlight: it is reasonable to keep < = 0 to prove that the time interval of wait has been reached, but it is also considered that if the client modifies the system time, the func function will be executed immediately.
      if (remaining <= 0 || remaining > wait) {
        // Due to the minimum time precision problem of setTimeout, there will be a time interval to wait, but the setTimeout operation set before has not been executed. Therefore, for the sake of insurance, the setTimeout operation is cleaned up first
        if (timeout) {
          clearTimeout(timeout);
          timeout = null;
        }
        previous = now;
        result = func.apply(context, args);
        if (!timeout) context = args = null;
      } else if (!timeout && options.trailing !== false) {
        // When options. Tracing = true, the func function is delayed
        timeout = setTimeout(later, remaining);
      }
      return result;
    };
  };

Simplified edition

var throttle = function ( fn, interval ) {
    var timer,
        first = true;
    return function () {
        var args = arguments,   // Rename it to prevent confusion
            _me = this;
        if ( first ) {      // First direct execution
            fn.apply(_me , args);
            return first = false;
        }
        if ( timer ){   // If the last execution is not finished, return directly
            return false;
        }
        timer = setTimeout(function () {  
            clearTimeout(timer);    // At the end of the time, cancel the timer and run the current function
            timer = null;
            fn.apply(_me, args);
        }, interval || 500);
    };
};

Reference articles

https://github.com/hk029/front-end/blob/master/about_js/optimize.md

Tags: github

Posted on Fri, 31 Jan 2020 07:14:09 -0800 by aniket_dj