summaryrefslogtreecommitdiffstats
path: root/lib/dom-batch.js
diff options
context:
space:
mode:
authorWilson Page <wilsonpage@me.com>2013-08-26 14:11:35 -0700
committerWilson Page <wilsonpage@me.com>2013-08-26 14:11:35 -0700
commit648e085853505e542826feab1fa71e43c37f7ee0 (patch)
tree1dd95a96358b310d2ecdcf3db0efc8d184c2a671 /lib/dom-batch.js
parent478dc440ea4b0d912c0e18ef36607ec0d08015d9 (diff)
parent8911faec035a5d4cd99b90f3a3a2eb77564f3ee1 (diff)
downloadfastdom-648e085853505e542826feab1fa71e43c37f7ee0.zip
fastdom-648e085853505e542826feab1fa71e43c37f7ee0.tar.gz
fastdom-648e085853505e542826feab1fa71e43c37f7ee0.tar.bz2
Merge pull request #3 from wilsonpage/rewrite
Rewrite
Diffstat (limited to 'lib/dom-batch.js')
-rw-r--r--lib/dom-batch.js169
1 files changed, 142 insertions, 27 deletions
diff --git a/lib/dom-batch.js b/lib/dom-batch.js
index 903033e..4671b80 100644
--- a/lib/dom-batch.js
+++ b/lib/dom-batch.js
@@ -1,38 +1,153 @@
-(function() {
- var domBatch = {};
- var reads = [];
- var writes = [];
- var batch;
-
- function call(fns) {
- var fn;
- while (fn = fns.shift()) fn();
+
+/**
+ * DOM-Batch
+ *
+ * Eliminates layout thrashing
+ * by batching DOM read/write
+ * interactions.
+ *
+ * @author Wilson Page <wilsonpage@me.com>
+ */
+
+;(function(){
+
+ 'use strict';
+
+ // RequestAnimationFrame Polyfill
+ var raf = window.requestAnimationFrame
+ || window.webkitRequestAnimationFrame
+ || window.mozRequestAnimationFrame
+ || function(cb) { window.setTimeout(cb, 1000 / 60); };
+
+ /**
+ * Creates a new
+ * DomBatch instance.
+ *
+ * (you should only have one
+ * instance per application).
+ *
+ * @constructor
+ */
+ function DomBatch() {
+ this.reads = [];
+ this.writes = [];
+ this.mode = null;
+ this.pending = false;
}
- domBatch.read = function(fn) {
- batch = batch || setBatch();
- reads.push(fn);
+ /**
+ * Adds a job to
+ * the read queue.
+ *
+ * @param {Function} fn
+ * @api public
+ */
+ DomBatch.prototype.read = function(fn) {
+ this.reads.push(fn);
+ this.request('read');
};
- domBatch.write = function(fn) {
- batch = batch || setBatch();
- writes.push(fn);
+ /**
+ * Adds a job to
+ * the write queue.
+ *
+ * @param {Function} fn
+ * @api public
+ */
+ DomBatch.prototype.write = function(fn) {
+ this.writes.push(fn);
+ this.request('write');
};
- function setBatch() {
- return setTimeout(function() {
- call(reads);
- call(writes);
- batch = null;
- }, 0);
- }
+ /**
+ * Makes the decision as to
+ * whether a the frame needs
+ * to be scheduled.
+ *
+ * @param {String} type
+ * @api private
+ */
+ DomBatch.prototype.request = function(type) {
+ 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 (this.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 (this.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 (this.mode === 'reading' && type === 'write') return;
+
+ // If there is already a frame
+ // scheduled, don't schedule another one
+ if (this.pending) return;
+
+ // Schedule frame (preserving context)
+ raf(function() { self.frame(); });
+
+ // Set flag to indicate
+ // a frame has been scheduled
+ this.pending = true;
+ };
+
+ /**
+ * Calls each job in
+ * the list passed.
+ *
+ * @param {Array} list
+ * @api private
+ */
+ DomBatch.prototype.run = function(list) {
+ while (list.length) {
+ list.shift().call(this);
+ }
+ };
+
+ /**
+ * Runs any read jobs followed
+ * by any write jobs.
+ *
+ * @api private
+ */
+ DomBatch.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;
+
+ // Set the mode to 'reading' so
+ // that we know we can add more
+ // reads to the queue instead of
+ // scheduling a new frame.
+ this.mode = 'reading';
+ this.run(this.reads);
+
+ // Set
+ this.mode = 'writing';
+ this.run(this.writes);
+
+ this.mode = null;
+ };
+
+ /**
+ * Expose 'DomBatch'
+ */
- // Expose the library
if (typeof exports === "object") {
- module.exports = domBatch;
+ module.exports = DomBatch;
} else if (typeof define === "function" && define.amd) {
- define(domBatch);
+ define(function(){ return DomBatch; });
} else {
- window['domBatch'] = domBatch;
+ window['DomBatch'] = DomBatch;
}
-}()); \ No newline at end of file
+
+})();