refactors Discourse.debounce

This commit is contained in:
Wojciech Zawistowski 2013-10-19 09:13:00 +02:00
parent aef4227073
commit d0f3765967
2 changed files with 21 additions and 40 deletions

View File

@ -1,6 +1,7 @@
/** /**
Debounce a Javascript function. This means if it's called many times in a time limit it Debounce a Javascript function. This means if it's called many times in a time limit it
should only be executed once. should only be executed once (at the end of the limit counted from the last call made).
Original function will be called with the context and arguments from the last call made.
@method debounce @method debounce
@module Discourse @module Discourse
@ -8,32 +9,16 @@
@param {Number} wait how long to wait @param {Number} wait how long to wait
**/ **/
Discourse.debounce = function(func, wait) { Discourse.debounce = function(func, wait) {
var timeout = null; var self, args;
var later = function() {
func.apply(self, args);
};
return function() { return function() {
var context = this; self = this;
var args = arguments; args = arguments;
var later = function() { Ember.run.debounce(null, later, wait);
timeout = null;
return func.apply(context, args);
};
if (timeout) return;
var currentWait;
if (typeof wait === "function") {
currentWait = wait();
} else {
currentWait = wait;
}
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(later, currentWait);
return timeout;
}; };
}; };

View File

@ -4,6 +4,10 @@ var firedOnce = function(message) {
ok(original.calledOnce, message); ok(original.calledOnce, message);
}; };
var firedTwice = function(message) {
ok(original.calledTwice, message);
};
var notFired = function(message) { var notFired = function(message) {
ok(!original.called, message); ok(!original.called, message);
}; };
@ -39,27 +43,20 @@ test("executes delayed function only once, no matter how many times debounced fu
firedOnce("second call was supressed"); firedOnce("second call was supressed");
}); });
test("does not prolong the timeout when the debounced function is called for the second time during the timeout", function() { test("prolongs the timeout when the debounced function is called for the second time during the timeout", function() {
debounced(); debounced();
clock.tick(50); clock.tick(50);
debounced(); debounced();
clock.tick(50); clock.tick(50);
firedOnce("function is executed exactly at the end of the original timeout"); notFired("at the end of the original timeout nothing happens");
});
test("returns a JS timer handle that allows delayed execution to be cancelled before the timeout ends", function() {
var timerId = debounced();
clock.tick(50); clock.tick(50);
clearTimeout(timerId); firedOnce("function is executed exactly at the end of the prolonged timeout");
clock.tick(50);
notFired("timeout has ended but function was not executed");
}); });
test("preserves first call's context and params when executing delayed function", function() { test("preserves last call's context and params when executing delayed function", function() {
var firstObj = {}; var firstObj = {};
var secondObj = {}; var secondObj = {};
@ -67,11 +64,11 @@ test("preserves first call's context and params when executing delayed function"
debounced.call(secondObj, "second"); debounced.call(secondObj, "second");
clock.tick(100); clock.tick(100);
ok(original.calledOn(firstObj), "the context of the first of two subsequent calls is preserved"); ok(original.calledOn(secondObj), "the context of the last of two subsequent calls is preserved");
ok(original.calledWithExactly("first"), "param passed during the first of two subsequent calls is preserved"); ok(original.calledWithExactly("second"), "param passed during the last of two subsequent calls is preserved");
}); });
test("can be called again (with a different context and params) after timeout passes", function() { test("can be called again after timeout passes", function() {
var firstObj = {}; var firstObj = {};
var secondObj = {}; var secondObj = {};
@ -81,6 +78,5 @@ test("can be called again (with a different context and params) after timeout pa
debounced.call(secondObj, "second"); debounced.call(secondObj, "second");
clock.tick(100); clock.tick(100);
ok(original.calledOn(secondObj), "function is executed with the context of the call made after the timeout has passed"); firedTwice();
ok(original.calledWithExactly("second"), "function is executed with the param passed to the call made after the timeout has passed");
}); });