diff options
author | Wilson Page <wilsonpage@me.com> | 2013-08-26 14:11:35 -0700 |
---|---|---|
committer | Wilson Page <wilsonpage@me.com> | 2013-08-26 14:11:35 -0700 |
commit | 648e085853505e542826feab1fa71e43c37f7ee0 (patch) | |
tree | 1dd95a96358b310d2ecdcf3db0efc8d184c2a671 /lib/dom-batch.js | |
parent | 478dc440ea4b0d912c0e18ef36607ec0d08015d9 (diff) | |
parent | 8911faec035a5d4cd99b90f3a3a2eb77564f3ee1 (diff) | |
download | fastdom-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.js | 169 |
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 + +})(); |