Permalink
Browse files

Avoid linear scan when adding new timer.

Timer callbacks are now assigned a unique id, such that if an existing callback
is later replaced, the timing parameters can be updated using a constant-time
lookup rather than a linear scan of the timer queue.
  • Loading branch information...
1 parent 428ea4f commit 443f0e648eaa9066350935c1058ab771877a3cf7 @mbostock mbostock committed Oct 4, 2012
Showing with 23 additions and 35 deletions.
  1. +7 −13 d3.v2.js
  2. +4 −4 d3.v2.min.js
  3. +12 −18 src/core/timer.js
View
20 d3.v2.js
@@ -622,6 +622,7 @@
var t0 = null, t1 = d3_timer_queue, then = Infinity;
while (t1) {
if (t1.flush) {
+ delete d3_timer_byId[t1.callback.id];
t1 = t0 ? t0.next = t1.next : d3_timer_queue = t1.next;
} else {
then = Math.min(then, t1.then + t1.delay);
@@ -4063,24 +4064,17 @@
return typeof b === "function" ? tweenFunction : b == null ? d3_tweenNull : (b += "", tweenString);
};
var d3_tweenRemove = {};
- var d3_timer_queue = null, d3_timer_interval, d3_timer_timeout;
+ var d3_timer_id = 0, d3_timer_byId = {}, d3_timer_queue = null, d3_timer_interval, d3_timer_timeout;
d3.timer = function(callback, delay, then) {
- var found = false, t0, t1 = d3_timer_queue;
if (arguments.length < 3) {
if (arguments.length < 2) delay = 0; else if (!isFinite(delay)) return;
then = Date.now();
}
- while (t1) {
- if (t1.callback === callback) {
- t1.then = then;
- t1.delay = delay;
- found = true;
- break;
- }
- t0 = t1;
- t1 = t1.next;
- }
- if (!found) d3_timer_queue = {
+ var timer = d3_timer_byId[callback.id];
+ if (timer && timer.callback === callback) {
+ timer.then = then;
+ timer.delay = delay;
+ } else d3_timer_byId[callback.id = ++d3_timer_id] = d3_timer_queue = {
callback: callback,
then: then,
delay: delay,
View
8 d3.v2.min.js
4 additions, 4 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
30 src/core/timer.js
@@ -1,33 +1,26 @@
-var d3_timer_queue = null,
+var d3_timer_id = 0,
+ d3_timer_byId = {},
+ d3_timer_queue = null,
d3_timer_interval, // is an interval (or frame) active?
d3_timer_timeout; // is a timeout active?
// The timer will continue to fire until callback returns true.
d3.timer = function(callback, delay, then) {
- var found = false,
- t0,
- t1 = d3_timer_queue;
-
if (arguments.length < 3) {
if (arguments.length < 2) delay = 0;
else if (!isFinite(delay)) return;
then = Date.now();
}
- // See if the callback's already in the queue.
- while (t1) {
- if (t1.callback === callback) {
- t1.then = then;
- t1.delay = delay;
- found = true;
- break;
- }
- t0 = t1;
- t1 = t1.next;
+ // If the callback's already in the queue, update it.
+ var timer = d3_timer_byId[callback.id];
+ if (timer && timer.callback === callback) {
+ timer.then = then;
+ timer.delay = delay;
}
// Otherwise, add the callback to the queue.
- if (!found) d3_timer_queue = {
+ else d3_timer_byId[callback.id = ++d3_timer_id] = d3_timer_queue = {
callback: callback,
then: then,
delay: delay,
@@ -40,7 +33,7 @@ d3.timer = function(callback, delay, then) {
d3_timer_interval = 1;
d3_timer_frame(d3_timer_step);
}
-}
+};
function d3_timer_step() {
var elapsed,
@@ -80,13 +73,14 @@ d3.timer.flush = function() {
d3_timer_flush();
};
-// Flush after callbacks, to avoid concurrent queue modification.
+// Flush after callbacks to avoid concurrent queue modification.
function d3_timer_flush() {
var t0 = null,
t1 = d3_timer_queue,
then = Infinity;
while (t1) {
if (t1.flush) {
+ delete d3_timer_byId[t1.callback.id];
t1 = t0 ? t0.next = t1.next : d3_timer_queue = t1.next;
} else {
then = Math.min(then, t1.then + t1.delay);

0 comments on commit 443f0e6

Please sign in to comment.