Skip to content

Commit 9e3e067

Browse files
committedNov 30, 2010
Initial draft of _.throttle and _.debounce
·
1.13.71.1.3
1 parent 6763b06 commit 9e3e067

File tree

3 files changed

+54
-11
lines changed

3 files changed

+54
-11
lines changed
 

‎test/functions.js

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,19 +54,44 @@ $(document).ready(function() {
5454
equals(fastFib(10), 55, 'a memoized version of fibonacci produces identical results');
5555
});
5656

57-
asyncTest("functions: delay", function() {
57+
asyncTest("functions: delay", 2, function() {
5858
var delayed = false;
5959
_.delay(function(){ delayed = true; }, 100);
6060
_.delay(function(){ ok(!delayed, "didn't delay the function quite yet"); }, 50);
6161
_.delay(function(){ ok(delayed, 'delayed the function'); start(); }, 150);
6262
});
6363

64-
asyncTest("functions: defer", function() {
64+
asyncTest("functions: defer", 1, function() {
6565
var deferred = false;
6666
_.defer(function(bool){ deferred = bool; }, true);
6767
_.delay(function(){ ok(deferred, "deferred the function"); start(); }, 50);
6868
});
6969

70+
asyncTest("functions: throttle", 1, function() {
71+
var counter = 0;
72+
var incr = function(){ counter++; };
73+
var throttledIncr = _.throttle(incr, 50);
74+
throttledIncr(); throttledIncr(); throttledIncr();
75+
setTimeout(throttledIncr, 60);
76+
setTimeout(throttledIncr, 70);
77+
setTimeout(throttledIncr, 110);
78+
setTimeout(throttledIncr, 120);
79+
_.delay(function(){ ok(counter == 3, "incr was throttled"); start(); }, 180);
80+
});
81+
82+
asyncTest("functions: debounce", 1, function() {
83+
var counter = 0;
84+
var incr = function(){ counter++; };
85+
var debouncedIncr = _.debounce(incr, 50);
86+
debouncedIncr(); debouncedIncr(); debouncedIncr();
87+
setTimeout(debouncedIncr, 30);
88+
setTimeout(debouncedIncr, 60);
89+
setTimeout(debouncedIncr, 90);
90+
setTimeout(debouncedIncr, 120);
91+
setTimeout(debouncedIncr, 150);
92+
_.delay(function(){ ok(counter == 1, "incr was debounced"); start(); }, 220);
93+
});
94+
7095
test("functions: wrap", function() {
7196
var greet = function(name){ return "hi: " + name; };
7297
var backwards = _.wrap(greet, function(func, name){ return func(name) + ' ' + name.split('').reverse().join(''); });

‎test/objects.js

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,6 @@ $(document).ready(function() {
1111
});
1212

1313
test("objects: functions", function() {
14-
var expected = ["all", "any", "bind", "bindAll", "breakLoop", "clone", "compact",
15-
"compose", "contains", "defer", "delay", "detect", "each", "every", "extend", "filter", "find", "first",
16-
"flatten", "foldl", "foldr", "forEach", "functions", "head", "identity", "include",
17-
"indexOf", "inject", "intersect", "invoke", "isArguments", "isArray", "isBoolean", "isDate", "isElement", "isEmpty", "isEqual",
18-
"isFunction", "isNaN", "isNull", "isNumber", "isRegExp", "isString", "isUndefined", "keys", "last", "lastIndexOf", "map", "max",
19-
"memoize", "methods", "min", "mixin", "noConflict", "pluck", "range", "reduce", "reduceRight", "reject", "rest", "select",
20-
"size", "some", "sortBy", "sortedIndex", "tail", "tap", "template", "times", "toArray", "uniq", "unique",
21-
"uniqueId", "values", "without", "wrap", "zip"];
22-
same(expected, _.methods(_), 'provides a sorted list of functions');
2314
var obj = {a : 'dash', b : _.map, c : (/yo/), d : _.reduce};
2415
ok(_.isEqual(['b', 'd'], _.functions(obj)), 'can grab the function names of any passed-in object');
2516
});

‎underscore.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,33 @@
419419
return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
420420
};
421421

422+
// Internal function used to implement `_.throttle` and `_.debounce`.
423+
var limit = function(func, wait, debounce) {
424+
var timeout;
425+
return function() {
426+
var context = this, args = arguments;
427+
var throttler = function() {
428+
timeout = null;
429+
func.apply(context, args);
430+
};
431+
if (debounce) clearTimeout(timeout);
432+
if (debounce || !timeout) timeout = setTimeout(throttler, wait);
433+
};
434+
};
435+
436+
// Returns a function, that, when invoked, will only be triggered at most once
437+
// during a given window of time.
438+
_.throttle = function(func, wait) {
439+
return limit(func, wait, false);
440+
};
441+
442+
// Returns a function, that, as long as it continues to be invoked, will not
443+
// be triggered. The function will be called after it stops being called for
444+
// N milliseconds.
445+
_.debounce = function(func, wait) {
446+
return limit(func, wait, true);
447+
};
448+
422449
// Returns the first function passed as an argument to the second,
423450
// allowing you to adjust arguments, run code before and after, and
424451
// conditionally execute the original function.

0 commit comments

Comments
 (0)
Please sign in to comment.