summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--.jshintignore1
-rw-r--r--.jshintrc11
-rw-r--r--.npmignore2
-rw-r--r--.travis.yml8
-rw-r--r--History.md8
-rw-r--r--README.md27
-rw-r--r--bower.json5
-rw-r--r--component.json4
-rw-r--r--index.js275
-rw-r--r--package.json5
-rw-r--r--test/test.clear.js25
-rw-r--r--test/test.defer.js84
-rw-r--r--test/test.set.js58
14 files changed, 346 insertions, 169 deletions
diff --git a/.gitignore b/.gitignore
index 28f1ba7..fd4f2b0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,2 @@
node_modules
-.DS_Store \ No newline at end of file
+.DS_Store
diff --git a/.jshintignore b/.jshintignore
new file mode 100644
index 0000000..3c3629e
--- /dev/null
+++ b/.jshintignore
@@ -0,0 +1 @@
+node_modules
diff --git a/.jshintrc b/.jshintrc
new file mode 100644
index 0000000..ebec543
--- /dev/null
+++ b/.jshintrc
@@ -0,0 +1,11 @@
+{
+ // Enforcing options
+ "camelcase": true,
+ "curly": false,
+ "quotmark": "single",
+
+ // Relaxing options
+ "boss": true,
+ "sub": true,
+ "laxbreak": true
+}
diff --git a/.npmignore b/.npmignore
index a806a83..cf940ae 100644
--- a/.npmignore
+++ b/.npmignore
@@ -1,3 +1,3 @@
/node_modules/
/examples/
-/test/ \ No newline at end of file
+/test/
diff --git a/.travis.yml b/.travis.yml
index 6212d53..f5eb376 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,5 @@
-script:
- - "npm test"
-
language: node_js
-
node_js:
- - "0.10" \ No newline at end of file
+ - "0.10"
+script:
+ - "npm test"
diff --git a/History.md b/History.md
index 68eeb5f..a21d6c3 100644
--- a/History.md
+++ b/History.md
@@ -1,4 +1,10 @@
+0.8.0 / 2013-10-14
+==================
+
+ * change to a rAF loop technique of emtying frame queue to prevent frame conflicts
+ * add ability to call `FastDom#defer` with no frame argument to schedule job for next free frame
+
0.7.1 / 2013-10-05
==================
@@ -11,4 +17,4 @@
* add `FastDom#clear` clears read, write and defer jobs by id
* remove `FastDom#clearRead`
* remove `FastDom#clearWrite`
- * change directory structure by removing `/lib` \ No newline at end of file
+ * change directory structure by removing `/lib`
diff --git a/README.md b/README.md
index 301a967..94fd10e 100644
--- a/README.md
+++ b/README.md
@@ -3,8 +3,6 @@
Eliminates layout thrashing by batching DOM read/write operations (~750 bytes gzipped).
```js
-var fastdom = new FastDom();
-
fastdom.read(function() {
console.log('read');
});
@@ -40,13 +38,13 @@ write
FastDom is CommonJS and AMD compatible, you can install it in one of the following ways:
-```
+``` sh
$ npm install fastdom
```
-```
+``` sh
$ bower install fastdom
```
-```
+``` sh
$ component install wilsonpage/fastdom
```
or [download](http://github.com/wilsonpage/fastdom/raw/master/index.js).
@@ -83,7 +81,7 @@ fastdom.write(function() {
});
```
-### FastDom#defer(frames, callback[, context])
+### FastDom#defer([frames,] callback[, context])
Defers a job for the number of frames specified. This is useful is you have a particualrly expensive piece of work to do, and don't want it to be done with all the other work.
@@ -93,6 +91,19 @@ For example; you are using third party library that doesn't expose an API that a
fastdom.defer(3, expensiveStuff);
```
+`FastDom#defer` can also be called with no `frames` argument to push work onto next avaiable frame.
+
+```js
+// Runs in frame 1
+fastdom.defer(expensiveStuff1);
+
+// Runs in frame 2
+fastdom.defer(expensiveStuff2);
+
+// Runs in frame 3
+fastdom.defer(expensiveStuff3);
+```
+
### FastDom#clear(id)
Clears **any** scheduled job by id.
@@ -111,7 +122,7 @@ fastdom.clear(defer);
#### With PhantomJS
-```
+``` sh
$ npm install
$ npm test
```
@@ -139,4 +150,4 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/bower.json b/bower.json
index d318c23..2319abf 100644
--- a/bower.json
+++ b/bower.json
@@ -1,7 +1,7 @@
{
"name": "fastdom",
"description": "Eliminates layout thrashing by batching DOM read/write operations",
- "version": "0.7.1",
+ "version": "0.8.0",
"main": "index.js",
"scripts": [
"index.js"
@@ -11,5 +11,6 @@
"test/",
"README.md"
],
- "license": "MIT"
+ "license": "MIT",
+ "_source": "git@github.com/wilsonpage/fastdom.git"
}
diff --git a/component.json b/component.json
index 82aa51f..a363a66 100644
--- a/component.json
+++ b/component.json
@@ -1,7 +1,7 @@
{
"name": "fastdom",
"description": "Eliminates layout thrashing by batching DOM read/write operations",
- "version": "0.7.1",
+ "version": "0.8.0",
"main": "index.js",
"scripts": [
"index.js"
@@ -12,4 +12,4 @@
"README.md"
],
"license": "MIT"
-} \ No newline at end of file
+}
diff --git a/index.js b/index.js
index 6be22f8..a077c06 100644
--- a/index.js
+++ b/index.js
@@ -1,6 +1,6 @@
/**
- * DOM-Batch
+ * FastDom
*
* Eliminates layout thrashing
* by batching DOM read/write
@@ -38,107 +38,153 @@
* @constructor
*/
function FastDom() {
+ this.frames = [];
this.lastId = 0;
- this.jobs = {};
this.mode = null;
- this.pending = false;
- this.queue = {
+ this.batch = {
+ hash: {},
read: [],
write: []
};
}
/**
- * Adds a job to
- * the read queue.
+ * Adds a job to the
+ * write batch and schedules
+ * a new frame if need be.
*
* @param {Function} fn
* @api public
*/
FastDom.prototype.read = function(fn, ctx) {
var job = this.add('read', fn, ctx);
- this.queue.read.push(job.id);
- this.request('read');
+
+ this.batch.read.push(job.id);
+
+ // If we're writing and a 'read' job
+ // comes in, we do have to schedule a new frame
+ var needsFrame = !this.batchPending || this.mode === 'writing';
+
+ // Schedule a new frame if need be
+ if (needsFrame) this.scheduleBatch();
+
return job.id;
};
/**
- * Adds a job to
- * the write queue.
+ * Adds a job to the
+ * write batch and schedules
+ * a new frame if need be.
*
* @param {Function} fn
* @api public
*/
FastDom.prototype.write = function(fn, ctx) {
var job = this.add('write', fn, ctx);
- this.queue.write.push(job.id);
- this.request('write');
+
+ this.batch.write.push(job.id);
+
+ // If we're emptying the read
+ // batch and a write comes in,
+ // we don't need to schedule a
+ // new frame. If we're writing
+ // and write comes in we don't
+ // need to schedule a new frame
+ var needsFrame = !this.batchPending;
+
+ // Schedule a new frame if need be
+ if (needsFrame) this.scheduleBatch();
+
return job.id;
};
/**
- * Removes a job from
- * the 'reads' queue.
+ * Defers the given job
+ * by the number of frames
+ * specified.
+ *
+ * If no frames are given
+ * then the job is run in
+ * the next free frame.
+ *
+ * @param {Number} frame
+ * @param {Function} fn
+ * @api public
+ */
+ FastDom.prototype.defer = function(frame, fn, ctx) {
+
+ // Accepts two arguments
+ if (typeof frame === 'function') {
+ ctx = fn;
+ fn = frame;
+ frame = 1;
+ }
+
+ var self = this;
+ var index = frame - 1;
+
+ return this.schedule(index, function() {
+ self.run({
+ fn: fn,
+ ctx: ctx
+ });
+ });
+ };
+
+ /**
+ * Clears a scheduled 'read',
+ * 'write' or 'defer' job.
*
* @param {Number} id
* @api public
*/
FastDom.prototype.clear = function(id) {
- var job = this.jobs[id];
- if (!job) return;
-
- // Clear reference
- delete this.jobs[id];
// Defer jobs are cleared differently
- if (job.type === 'defer') {
- caf(job.timer);
- return;
+ if (typeof id === 'function') {
+ return this.clearFrame(id);
}
- var list = this.queue[job.type];
+ var job = this.batch.hash[id];
+ if (!job) return;
+
+ var list = this.batch[job.type];
var index = list.indexOf(id);
+
+ // Clear references
+ delete this.batch.hash[id];
if (~index) list.splice(index, 1);
};
/**
- * Makes the decision as to
- * whether a the frame needs
- * to be scheduled.
+ * Clears a scheduled frame.
*
- * @param {String} type
+ * @param {Function} frame
* @api private
*/
- FastDom.prototype.request = function(type) {
- var mode = this.mode;
- var self = this;
-
- // If we are currently writing, we don't
- // need to scedule a new frame as this
- // job will be emptied from the write queue
- if (mode === 'writing' && type === 'write') return;
-
- // If we are reading we don't need to schedule
- // a new frame as this read will be emptied
- // in the currently active read queue
- if (mode === 'reading' && type === 'read') return;
-
- // If we are reading we don't need to schedule
- // a new frame and this write job will be run
- // after the read queue has been emptied in the
- // currently active frame.
- if (mode === 'reading' && type === 'write') return;
+ FastDom.prototype.clearFrame = function(frame) {
+ var index = this.frames.indexOf(frame);
+ if (~index) this.frames.splice(index, 1);
+ };
- // If there is already a frame
- // scheduled, don't schedule another one
- if (this.pending) return;
+ /**
+ * Schedules a new read/write
+ * batch if one isn't pending.
+ *
+ * @api private
+ */
+ FastDom.prototype.scheduleBatch = function() {
+ var self = this;
- // Schedule frame (preserving context)
- raf(function() { self.frame(); });
+ // Schedule batch for next frame
+ this.schedule(0, function() {
+ self.runBatch();
+ self.batchPending = false;
+ });
// Set flag to indicate
// a frame has been scheduled
- this.pending = true;
+ this.batchPending = true;
};
/**
@@ -167,7 +213,7 @@
FastDom.prototype.flush = function(list) {
var id;
while (id = list.shift()) {
- this.run(this.jobs[id]);
+ this.run(this.batch.hash[id]);
}
};
@@ -177,55 +223,24 @@
*
* @api private
*/
- FastDom.prototype.frame = function() {
-
- // Set the pending flag to
- // false so that any new requests
- // that come in will schedule a new frame
- this.pending = false;
+ FastDom.prototype.runBatch = function() {
// Set the mode to 'reading',
// then empty all read jobs
this.mode = 'reading';
- this.flush(this.queue.read);
+ this.flush(this.batch.read);
// Set the mode to 'writing'
// then empty all write jobs
this.mode = 'writing';
- this.flush(this.queue.write);
+ this.flush(this.batch.write);
this.mode = null;
};
/**
- * Defers the given job
- * by the number of frames
- * specified.
- *
- * @param {Number} frames
- * @param {Function} fn
- * @api public
- */
- FastDom.prototype.defer = function(frames, fn, ctx) {
- if (frames < 0) return;
- var job = this.add('defer', fn, ctx);
- var self = this;
-
- (function wrapped() {
- if (!(frames--)) {
- self.run(job);
- return;
- }
-
- job.timer = raf(wrapped);
- })();
-
- return job.id;
- };
-
- /**
* Adds a new job to
- * the given queue.
+ * the given batch.
*
* @param {Array} list
* @param {Function} fn
@@ -235,7 +250,7 @@
*/
FastDom.prototype.add = function(type, fn, ctx) {
var id = this.uniqueId();
- return this.jobs[id] = {
+ return this.batch.hash[id] = {
id: id,
fn: fn,
ctx: ctx,
@@ -244,17 +259,8 @@
};
/**
- * Called when a callback errors.
- * Overwrite this if you don't
- * want errors inside your jobs
- * to fail silently.
- *
- * @param {Error}
- */
- FastDom.prototype.onError = function(){};
-
- /**
* Runs a given job.
+ *
* @param {Object} job
* @api private
*/
@@ -262,14 +268,75 @@
var ctx = job.ctx || this;
// Clear reference to the job
- delete this.jobs[job.id];
+ delete this.batch.hash[job.id];
- // Call the job in
- try { job.fn.call(ctx); } catch(e) {
- this.onError(e);
+ if (this.quiet) {
+ try { job.fn.call(ctx); } catch (e) {}
+ } else {
+ job.fn.call(ctx);
}
};
+ /**
+ * Starts of a rAF loop
+ * to empty the frame queue.
+ *
+ * @api private
+ */
+ FastDom.prototype.loop = function() {
+ var self = this;
+
+ // Don't start more than one loop
+ if (this.looping) return;
+
+ raf(function frame() {
+ var fn = self.frames.shift();
+
+ // Run the frame
+ if (fn) fn();
+
+ // If no more frames,
+ // stop looping
+ if (!self.frames.length) {
+ self.looping = false;
+ return;
+ }
+
+ raf(frame);
+ });
+
+ this.looping = true;
+ };
+
+ /**
+ * Adds a function to
+ * a specified index
+ * of the frame queue.
+ *
+ * @param {Number} index
+ * @param {Function} fn
+ * @return {Function}
+ */
+ FastDom.prototype.schedule = function(index, fn) {
+
+ // Make sure this slot
+ // hasn't already been
+ // taken. If it has, try
+ // re-scheduling for the next slot
+ if (this.frames[index]) {
+ return this.schedule(index + 1, fn);
+ }
+
+ // Start the rAF
+ // loop to empty
+ // the frame queue
+ this.loop();
+
+ // Insert this function into
+ // the frames queue and return
+ return this.frames[index] = fn;
+ };
+
// We only ever want there to be
// one instance of FastDom in an app
fastdom = fastdom || new FastDom();
@@ -280,7 +347,7 @@
if (typeof module !== 'undefined' && module.exports) {
module.exports = fastdom;
- } else if (typeof define === "function" && define.amd) {
+ } else if (typeof define === 'function' && define.amd) {
define(function(){ return fastdom; });
} else {
window['fastdom'] = fastdom;
diff --git a/package.json b/package.json
index e4ea0f3..84ddb9a 100644
--- a/package.json
+++ b/package.json
@@ -1,10 +1,10 @@
{
"name": "fastdom",
"description": "Eliminates layout thrashing by batching DOM read/write operations",
- "version": "0.7.1",
+ "version": "0.8.0",
"main": "index.js",
"scripts": {
- "test": "./node_modules/.bin/mocha-phantomjs test/index.html"
+ "test": "jshint . && mocha-phantomjs test/index.html"
},
"homepage": "https://github.com/wilsonpage/fastdom",
"author": {
@@ -18,6 +18,7 @@
"license": "MIT",
"devDependencies": {
"mocha": "~1.12.0",
+ "jshint": "~2.1.0",
"sinon": "~1.7.3",
"chai": "~1.7.2",
"mocha-phantomjs": "~3.1.2"
diff --git a/test/test.clear.js b/test/test.clear.js
index ee60f2e..f0f60b1 100644
--- a/test/test.clear.js
+++ b/test/test.clear.js
@@ -1,7 +1,7 @@
-suite('Clear', function(){
+suite('clear', function(){
- test("Should not run 'read' job if cleared (sync)", function(done) {
+ test('Should not run "read" job if cleared (sync)', function(done) {
var fastdom = new FastDom();
var read = sinon.spy();
@@ -14,7 +14,7 @@ suite('Clear', function(){
});
});
- test("Should fail silently if job not found in queue", function(done) {
+ test('Should fail silently if job not found in queue', function(done) {
var fastdom = new FastDom();
var read = sinon.spy();
var read2 = sinon.spy();
@@ -28,7 +28,7 @@ suite('Clear', function(){
});
});
- test("Should not run 'write' job if cleared (async)", function(done) {
+ test('Should not run "write" job if cleared (async)', function(done) {
var fastdom = new FastDom();
var read = sinon.spy();
var write = sinon.spy();
@@ -44,7 +44,7 @@ suite('Clear', function(){
});
});
- test("Should not run 'write' job if cleared", function(done) {
+ test('Should not run "write" job if cleared', function(done) {
var fastdom = new FastDom();
var write = sinon.spy();
var id = fastdom.write(write);
@@ -57,10 +57,10 @@ suite('Clear', function(){
});
});
- test("Should not run 'defer' job if cleared", function(done) {
+ test('Should not run "defer" job if cleared', function(done) {
var fastdom = new FastDom();
- var write = sinon.spy();
- var id = fastdom.defer(3, write);
+ var callback = sinon.spy();
+ var id = fastdom.defer(3, callback);
fastdom.clear(id);
@@ -68,7 +68,7 @@ suite('Clear', function(){
raf(function() {
raf(function() {
raf(function() {
- assert(!write.called);
+ assert(!callback.called);
done();
});
});
@@ -76,10 +76,10 @@ suite('Clear', function(){
});
});
- test("Should remove reference to the job if cleared", function(done) {
+ test('Should remove reference to the job if cleared', function(done) {
var fastdom = new FastDom();
var write = sinon.spy();
- var id = fastdom.defer(2, write);
+ var id = fastdom.write(2, write);
fastdom.clear(id);
@@ -87,11 +87,10 @@ suite('Clear', function(){
raf(function() {
raf(function() {
assert(!write.called);
- assert(!fastdom.jobs[id]);
+ assert(!fastdom.batch.hash[id]);
done();
});
});
});
});
-
}); \ No newline at end of file
diff --git a/test/test.defer.js b/test/test.defer.js
index c1ae179..114287f 100644
--- a/test/test.defer.js
+++ b/test/test.defer.js
@@ -1,28 +1,25 @@
suite('defer', function(){
- test("Should run the job after the specified number of frames", function(done) {
+ test('Should run the job after the specified number of frames', function(done) {
var fastdom = new FastDom();
var job = sinon.spy();
- fastdom.defer(4, job);
+ fastdom.defer(3, job);
raf(function() {
assert(!job.called);
raf(function() {
assert(!job.called);
raf(function() {
- assert(!job.called);
- raf(function() {
- assert(job.called);
- done();
- });
+ assert(job.called);
+ done();
});
});
});
});
- test("Should call a deferred callback with the given context", function(done) {
+ test('Should call a deferred callback with the given context', function(done) {
var fastdom = new FastDom();
var cb = sinon.spy();
var ctx = { foo: 'bar' };
@@ -33,18 +30,81 @@ suite('defer', function(){
}, ctx);
});
- test("Should remove the reference to the job once run", function(done) {
+ test('Should run work at next frame if frames argument not supplied.', function(done) {
var fastdom = new FastDom();
- var callback = sinon.spy();
- var id = fastdom.defer(2, callback);
+ var callback1 = sinon.spy();
+ var callback2 = sinon.spy();
+
+ fastdom.defer(callback1);
raf(function() {
+ assert(callback1.called);
+ done();
+ });
+ });
+
+ test('Should run each job on a different frame.', function(done) {
+ var fastdom = new FastDom();
+ var callback1 = sinon.spy();
+ var callback2 = sinon.spy();
+ var callback3 = sinon.spy();
+
+ fastdom.defer(callback1);
+ fastdom.defer(callback2);
+ fastdom.defer(callback3);
+
+ raf(function() {
+ assert(callback1.called);
+ assert(!callback2.called);
+ assert(!callback3.called);
raf(function() {
+ assert(callback2.called);
+ assert(!callback3.called);
raf(function() {
- assert(!fastdom.jobs[id]);
+ assert(callback3.called);
done();
});
});
});
});
+
+ test('Should run fill empty frames before later work is run.', function(done) {
+ var fastdom = new FastDom();
+ var callback1 = sinon.spy();
+ var callback2 = sinon.spy();
+ var callback3 = sinon.spy();
+ var callback4 = sinon.spy();
+
+ // Frame 3
+ fastdom.defer(3, callback3);
+
+ // Frame 1
+ fastdom.defer(callback1);
+
+ // Frame 2
+ fastdom.defer(callback2);
+
+ // Frame 4
+ fastdom.defer(callback4);
+
+ raf(function() {
+ assert(callback1.called);
+ assert(!callback2.called);
+ assert(!callback3.called);
+ assert(!callback4.called);
+ raf(function() {
+ assert(callback2.called);
+ assert(!callback3.called);
+ assert(!callback4.called);
+ raf(function() {
+ assert(callback3.called);
+ assert(!callback4.called);
+ raf(function() {
+ assert(callback4.called);
+ done();
+ });
+ });
+ });
+ });
+ });
});
diff --git a/test/test.set.js b/test/test.set.js
index a1dd83c..a41259a 100644
--- a/test/test.set.js
+++ b/test/test.set.js
@@ -1,7 +1,7 @@
-suite('Set', function() {
+suite('set', function() {
- test("Should run reads before writes", function(done) {
+ test('Should run reads before writes', function(done) {
var fastdom = new FastDom();
var read = sinon.spy(function() {
@@ -17,7 +17,7 @@ suite('Set', function() {
fastdom.write(write);
});
- test("Should call all reads together, followed by all writes", function(done) {
+ test('Should call all reads together, followed by all writes', function(done) {
var fastdom = new FastDom();
var read1 = sinon.spy();
var read2 = sinon.spy();
@@ -41,7 +41,7 @@ suite('Set', function() {
});
});
- test("Should call a read in the same frame if scheduled inside a read callback", function(done) {
+ test('Should call a read in the same frame if scheduled inside a read callback', function(done) {
var fastdom = new FastDom();
var cb = sinon.spy();
@@ -59,11 +59,17 @@ suite('Set', function() {
assert(!cb.called);
done();
});
+
+ // Should not have scheduled a new frame
+ assert(fastdom.frames.length === 0);
});
});
- test("Should call a write in the same frame if scheduled inside a read callback", function(done) {
+ test('Should call a write in the same frame if scheduled inside a read callback', function(done) {
var fastdom = new FastDom();
+
+ fastdom.catchErrors = false;
+
var cb = sinon.spy();
fastdom.read(function() {
@@ -80,10 +86,13 @@ suite('Set', function() {
assert(!cb.called);
done();
});
+
+ // Should not have scheduled a new frame
+ assert(fastdom.frames.length === 0);
});
});
- test("Should call a read in the *next* frame if scheduled inside a write callback", function(done) {
+ test('Should call a read in the *next* frame if scheduled inside a write callback', function(done) {
var fastdom = new FastDom();
var cb = sinon.spy();
@@ -100,10 +109,13 @@ suite('Set', function() {
assert(cb.called);
done();
});
+
+ // Should not have scheduled a new frame
+ assert(fastdom.frames.length === 1);
});
});
- test("Should call a 'read' callback with the given context", function(done) {
+ test('Should call a "read" callback with the given context', function(done) {
var fastdom = new FastDom();
var cb = sinon.spy();
var ctx = { foo: 'bar' };
@@ -114,7 +126,7 @@ suite('Set', function() {
}, ctx);
});
- test("Should call a 'write' callback with the given context", function(done) {
+ test('Should call a "write" callback with the given context', function(done) {
var fastdom = new FastDom();
var cb = sinon.spy();
var ctx = { foo: 'bar' };
@@ -125,7 +137,7 @@ suite('Set', function() {
}, ctx);
});
- test("Should have empty job hash when batch complete", function(done) {
+ test('Should have empty job hash when batch complete', function(done) {
var fastdom = new FastDom();
fastdom.read(function(){});
@@ -134,15 +146,15 @@ suite('Set', function() {
fastdom.write(function(){});
// Check there are four jobs stored
- assert.equal(objectLength(fastdom.jobs), 4);
+ assert.equal(objectLength(fastdom.batch.hash), 4);
raf(function() {
- assert.equal(objectLength(fastdom.jobs), 0);
+ assert.equal(objectLength(fastdom.batch.hash), 0);
done();
});
});
- test("Should maintain correct context if single method is registered twice", function(done) {
+ test('Should maintain correct context if single method is registered twice', function(done) {
var fastdom = new FastDom();
var ctx1 = { foo: 'bar' };
var ctx2 = { bar: 'baz' };
@@ -162,12 +174,12 @@ suite('Set', function() {
});
});
- test("Should call a registered onError handler when an error is thrown inside a job", function(done) {
+ test('Should no error if the `quiet` flag is set', function(done) {
var fastdom = new FastDom();
var err1 = { some: 'error1' };
var err2 = { some: 'error2' };
- fastdom.onError = sinon.spy();
+ fastdom.quiet = true;
fastdom.read(function() {
throw err1;
@@ -178,10 +190,20 @@ suite('Set', function() {
});
raf(function() {
- assert(fastdom.onError.calledTwice);
- assert(fastdom.onError.getCall(0).calledWith(err1));
- assert(fastdom.onError.getCall(1).calledWith(err2));
done();
});
});
-}); \ No newline at end of file
+
+ test('Should stop rAF loop once frame queue is empty', function(done) {
+ var fastdom = new FastDom();
+ var callback = sinon.spy();
+
+ fastdom.read(callback);
+
+ raf(function() {
+ assert(callback.called);
+ assert(fastdom.looping === false);
+ done();
+ });
+ });
+});