Reputation: 31
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
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
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