Skip to content

Commit

Permalink
Optimizations.
Browse files Browse the repository at this point in the history
Private state on the timer object; avoid try-finally.
  • Loading branch information
mbostock committed Feb 9, 2016
1 parent 1e7ee4c commit fb43e7d
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 49 deletions.
8 changes: 2 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This module provides an efficient queue capable of managing thousands of concurr
If you use NPM, `npm install d3-timer`. Otherwise, download the [latest release](https://github.com/d3/d3-timer/releases/latest). The released bundle supports AMD, CommonJS, and vanilla environments. Create a custom build using [Rollup](https://github.com/rollup/rollup) or your preferred bundler. You can also load directly from [d3js.org](https://d3js.org):

```html
<script src="https://d3js.org/d3-timer.v0.1.min.js"></script>
<script src="https://d3js.org/d3-timer.v0.2.min.js"></script>
```

In a vanilla environment, a `d3_timer` global is exported. [Try d3-timer in your browser.](https://tonicdev.com/npm/d3-timer)
Expand Down Expand Up @@ -55,16 +55,12 @@ If [timer](#timer) is called within the callback of another timer, the new timer

<a name="timer_restart" href="#timer_restart">#</a> <i>timer</i>.<b>restart</b>(<i>callback</i>[, <i>delay</i>[, <i>time</i>]])

Restart a timer with the specified *callback* and optional *delay* and *time*. This is equivalent to stopping this timer and creating a new timer with the specified arguments, although this timer retains the original [id](#timer_id) and invocation priority.
Restart a timer with the specified *callback* and optional *delay* and *time*. This is equivalent to stopping this timer and creating a new timer with the specified arguments, although this timer retains the original invocation priority.

<a name="timer_stop" href="#timer_stop">#</a> <i>timer</i>.<b>stop</b>()

Stops this timer, preventing subsequent callbacks. This method has no effect if the timer has already stopped.

<a name="timer_id" href="#timer_id">#</a> <i>timer</i>.<b>id</b>

An opaque, unique identifier for this timer.

<a name="timerOnce" href="#timerOnce">#</a> d3.<b>timerOnce</b>(<i>callback</i>[, <i>delay</i>[, <i>time</i>]])

Like [timer](#timer), except the timer automatically [stops](#timer_stop) on its first callback.
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "d3-timer",
"version": "0.1.2",
"version": "0.2.0",
"description": "An efficient queue capable of managing thousands of concurrent animations.",
"keywords": [
"d3",
Expand All @@ -27,7 +27,7 @@
"pretest": "mkdir -p build && node -e 'process.stdout.write(\"var version = \\\"\" + require(\"./package.json\").version + \"\\\"; export * from \\\"../index\\\"; export {version};\");' > build/bundle.js && rollup -f umd -n d3_timer -o build/d3-timer.js -- build/bundle.js",
"test": "faucet `find test -name '*-test.js'` && eslint index.js src",
"prepublish": "npm run test && uglifyjs build/d3-timer.js -c -m -o build/d3-timer.min.js && rm -f build/d3-timer.zip && zip -j build/d3-timer.zip -- LICENSE README.md build/d3-timer.js build/d3-timer.min.js",
"postpublish": "VERSION=`node -e 'console.log(require(\"./package.json\").version)'`; git push && git tag -am \"Release $VERSION.\" v${VERSION} && git push --tags && cp build/d3-timer.js ../d3.github.com/d3-timer.v0.1.js && cp build/d3-timer.min.js ../d3.github.com/d3-timer.v0.1.min.js && cd ../d3.github.com && git add d3-timer.v0.1.js d3-timer.v0.1.min.js && git commit -m \"d3-timer ${VERSION}\" && git push"
"postpublish": "VERSION=`node -e 'console.log(require(\"./package.json\").version)'`; git push && git tag -am \"Release $VERSION.\" v${VERSION} && git push --tags && cp build/d3-timer.js ../d3.github.com/d3-timer.v0.2.js && cp build/d3-timer.min.js ../d3.github.com/d3-timer.v0.2.min.js && cd ../d3.github.com && git add d3-timer.v0.2.js d3-timer.v0.2.min.js && git commit -m \"d3-timer ${VERSION}\" && git push"
},
"devDependencies": {
"faucet": "0.0",
Expand Down
66 changes: 33 additions & 33 deletions src/timer.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
var frame = 0, // is an animation frame pending?
timeout = 0, // is a timeout pending?
taskHead,
taskTail,
taskId = 0,
taskById = {};
taskTail;

var setFrame = typeof window !== "undefined"
&& (window.requestAnimationFrame
Expand All @@ -14,28 +12,28 @@ var setFrame = typeof window !== "undefined"
|| function(callback) { return setTimeout(callback, 17); };

function Timer() {
this.id = ++taskId;
this._call =
this._time =
this._next = null;
}

Timer.prototype = timer.prototype = {
restart: function(callback, delay, time) {
if (typeof callback !== "function") throw new TypeError("callback is not a function");
time = (time == null ? Date.now() : +time) + (delay == null ? 0 : +delay);
var i = this.id, t = taskById[i];
if (t) {
t.callback = callback, t.time = time;
} else {
t = {next: null, callback: callback, time: time};
if (taskTail) taskTail.next = t; else taskHead = t;
taskById[i] = taskTail = t;
if (!this._call) {
if (taskTail) taskTail._next = this;
else taskHead = this;
taskTail = this;
}
this._call = callback;
this._time = time;
sleep();
},
stop: function() {
var i = this.id, t = taskById[i];
if (t) {
t.callback = null, t.time = Infinity;
delete taskById[i];
if (this._call) {
this._call = null;
this._time = Infinity;
sleep();
}
}
Expand All @@ -56,33 +54,35 @@ export function timerOnce(callback, delay, time) {
export function timerFlush(now) {
now = now == null ? Date.now() : +now;
++frame; // Pretend we’ve set an alarm, if we haven’t already.
try {
var t = taskHead, c;
while (t) {
if (now >= t.time) c = t.callback, c(now - t.time, now);
t = t.next;
var t = taskHead;
while (t) {
if (now >= t._time) t._call.call(null, now - t._time, now);
t = t._next;
}
--frame;
}

function timerSweep() {
var t0, t1 = taskHead, time = Infinity;
while (t1) {
if (t1._call) {
if (time > t1._time) time = t1._time;
t1 = (t0 = t1)._next;
} else {
t1 = t0 ? t0._next = t1._next : taskHead = t1._next;
}
} finally {
--frame;
}
taskTail = t0;
return time;
}

function wake() {
frame = timeout = 0;
try {
timerFlush();
} finally {
var t0, t1 = taskHead, time = Infinity;
while (t1) {
if (t1.callback) {
if (time > t1.time) time = t1.time;
t1 = (t0 = t1).next;
} else {
t1 = t0 ? t0.next = t1.next : taskHead = t1.next;
}
}
taskTail = t0;
sleep(time);
frame = 0;
sleep(timerSweep());
}
}

Expand Down
8 changes: 0 additions & 8 deletions test/timer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -387,11 +387,3 @@ tape("timer.restart(callback, delay, time) recomputes the new wake time after on
}, 100);
}, 100);
});

tape("timer.id is a positive integer", function(test) {
var t = timer.timer(function() {});
test.ok(t.id > 0);
test.equal(t.id % 1, 0);
t.stop();
end(test);
});

0 comments on commit fb43e7d

Please sign in to comment.