Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple throttle in JavaScript

I am looking for a simple throttle in JavaScript. I know libraries like lodash and underscore have it, but only for one function it will be overkill to include any of those libraries.

I was also checking if jQuery has a similar function - could not find.

I have found one working throttle, and here is the code:

function throttle(fn, threshhold, scope) {
  threshhold || (threshhold = 250);
  var last,
      deferTimer;
  return function () {
    var context = scope || this;

    var now = +new Date,
        args = arguments;
    if (last && now < last + threshhold) {
      // hold on to it
      clearTimeout(deferTimer);
      deferTimer = setTimeout(function () {
        last = now;
        fn.apply(context, args);
      }, threshhold);
    } else {
      last = now;
      fn.apply(context, args);
    }
  };
}

The problem with this is: it fires the function once more after the throttle time is complete. So let's assume I made a throttle that fires every 10 seconds on keypress - if I do keypress 2 times, it will still fire the second keypress when 10 seconds are completed. I do not want this behavior.

like image 949
Mia Avatar asked Nov 22 '14 14:11

Mia


People also ask

How do I use throttle in JavaScript?

Implement a Throttle Function With Vanilla JavaScriptInitialize a variable to detect if the function has been called within the specified time. If the function has been called, pause the throttle function. If the function hasn't been called or is done running in the interval, rerun the throttle function.

What is Debouncing and throttling in JS?

Debouncing is a technique where we can monitor the time delay of user action and once that delay reaches our predetermined threshold we can can make the function call. Throttling is a technique where we make the function call in a predetermined time interval irrespective of continuous user actions.

What is throttling in programming?

To throttle a function means to ensure that the function is called at most once in a specified time period (for instance, once every 10 seconds). This means throttling will prevent a function from running if it has run “recently”. Throttling also ensures a function is run regularly at a fixed rate.


3 Answers

I would use the underscore.js or lodash source code to find a well tested version of this function.

Here is the slightly modified version of the underscore code to remove all references to underscore.js itself:

// Returns a function, that, when invoked, will only be triggered at most once
// during a given window of time. Normally, the throttled function will run
// as much as it can, without ever going more than once per `wait` duration;
// but if you'd like to disable the execution on the leading edge, pass
// `{leading: false}`. To disable execution on the trailing edge, ditto.
function throttle(func, wait, options) {
  var context, args, result;
  var timeout = null;
  var previous = 0;
  if (!options) options = {};
  var later = function() {
    previous = options.leading === false ? 0 : Date.now();
    timeout = null;
    result = func.apply(context, args);
    if (!timeout) context = args = null;
  };
  return function() {
    var now = Date.now();
    if (!previous && options.leading === false) previous = now;
    var remaining = wait - (now - previous);
    context = this;
    args = arguments;
    if (remaining <= 0 || remaining > wait) {
      if (timeout) {
        clearTimeout(timeout);
        timeout = null;
      }
      previous = now;
      result = func.apply(context, args);
      if (!timeout) context = args = null;
    } else if (!timeout && options.trailing !== false) {
      timeout = setTimeout(later, remaining);
    }
    return result;
  };
};

Please note that this code can be simplified if you don't need all the options that underscore support.

Please find below a very simple and non-configurable version of this function:

function throttle (callback, limit) {
    var waiting = false;                      // Initially, we're not waiting
    return function () {                      // We return a throttled function
        if (!waiting) {                       // If we're not waiting
            callback.apply(this, arguments);  // Execute users function
            waiting = true;                   // Prevent future invocations
            setTimeout(function () {          // After a period of time
                waiting = false;              // And allow future invocations
            }, limit);
        }
    }
}

Edit 1: Removed another reference to underscore, thx to @Zettam 's comment

Edit 2: Added suggestion about lodash and possible code simplification, thx to @lolzery @wowzery 's comment

Edit 3: Due to popular requests, I added a very simple, non-configurable version of the function, adapted from @vsync 's comment

like image 174
Clément Prévost Avatar answered Oct 17 '22 21:10

Clément Prévost


What about this?

function throttle(func, timeFrame) {
  var lastTime = 0;
  return function () {
      var now = Date.now();
      if (now - lastTime >= timeFrame) {
          func();
          lastTime = now;
      }
  };
}

Simple.

You may be interested in having a look at the source.

like image 31
smartmouse Avatar answered Oct 17 '22 21:10

smartmouse


callback: takes the function that should be called

limit: number of times that function should be called within the time limit

time: time span to reset the limit count

functionality and usage: Suppose you have an API that allows user to call it 10 times in 1 minute

function throttling(callback, limit, time) {
    /// monitor the count
    var calledCount = 0;

    /// refresh the `calledCount` varialbe after the `time` has been passed
    setInterval(function(){ calledCount = 0 }, time);

    /// creating a closure that will be called
    return function(){
        /// checking the limit (if limit is exceeded then do not call the passed function
        if (limit > calledCount) {
            /// increase the count
            calledCount++;
            callback(); /// call the function
        } 
        else console.log('not calling because the limit has exceeded');
    };
}
    
//////////////////////////////////////////////////////////// 
// how to use

/// creating a function to pass in the throttling function 
function cb(){
    console.log("called");
}

/// calling the closure function in every 100 milliseconds
setInterval(throttling(cb, 3, 1000), 100);
like image 14
Vikas Bansal Avatar answered Oct 17 '22 21:10

Vikas Bansal