rumirumi
rumirumi

Reputation: 31

Inner function context in underscore.js debounce function

I am trying to understand the mechanism of underscore.js debounce function: http://underscorejs.org/#debounce

Here is its native code:

_.debounce = function(func, wait, immediate) {
    var timeout, args, context, timestamp, result;

    var later = function() {
      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();
      var callNow = immediate && !timeout;
      if (!timeout) timeout = setTimeout(later, wait);
      if (callNow) {
        result = func.apply(context, args);
        context = args = null;
      }

      return result;
    };
  };

The thing I got stuck with is the context variable used in the inner returnable function. I can not understand why we should use it here and what context it contains. I tried to use the same function with the simple call of debounced function without applying any context to it and it also worked well. Here is my small fiddle with these two functions: http://jsfiddle.net/vlrt/fby9dhe0/11/

So, is the context necessary here? What context is needed to be applied?

Upvotes: 0

Views: 2272

Answers (2)

Nick Chen
Nick Chen

Reputation: 1

Can you give any concrete examples? here is my code but 1. apply(context, args); 2. func(); they console the same but they should not?

function debounce(func, wait, immediate) {
  // 'private' variable for instance
  // The returned function will be able to reference this due to closure.
  // Each call to the returned function will share this common timer.
  var timeout;
  this.a =222;
  // Calling debounce returns a new anonymous function
  return function() {
    // reference the context and args for the setTimeout function
    var context = this,
      args = arguments;

    // Should the function be called now? If immediate is true
    //   and not already in a timeout then the answer is: Yes
    var callNow = immediate && !timeout;

    // This is the basic debounce behaviour where you can call this 
    //   function several times, but it will only execute once 
    //   [before or after imposing a delay]. 
    //   Each time the returned function is called, the timer starts over.
    clearTimeout(timeout);

    // Set the new timeout
    timeout = setTimeout(function() {

      // Inside the timeout function, clear the timeout variable
      // which will let the next execution run when in 'immediate' mode
      timeout = null;

      // Check if the function already ran with the immediate flag
      if (!immediate) {
        // Call the original function with apply
        // apply lets you define the 'this' object as well as the arguments 
        //    (both captured before setTimeout)
        func.apply(context, args);
        func();
      }
    }, wait);

    // Immediate mode and no wait timer? Execute the function..
    if (callNow) func.apply(context, args);
  }
}

function test() {
    this.a = 100;
    this.b = 200;
}
test.prototype.m1 = function() {
    console.log("m1", this.a);
}
var tt = new test();
debounce(tt.m1, 1000)();

Upvotes: 0

user663031
user663031

Reputation:

Context is the this with which the debounced version of the function was called. If we are debouncing a method on an object, then we will call it with object.debounced_function, but we want the original function to be called with that same object as this.

If the debounced function is not an object method, or is called with no this, then context will be null or window or something, and the original function will be called with that as this, but nobody will care.

I assume you understand the Function#apply method, which calls a function with a particular context (this) and set of arguments.

Upvotes: 1

Related Questions