diff --git a/src/FirebaseArray.js b/src/FirebaseArray.js index dc4889e4..f67ddbfe 100644 --- a/src/FirebaseArray.js +++ b/src/FirebaseArray.js @@ -624,14 +624,13 @@ } var def = $firebaseUtils.defer(); - var batch = $firebaseUtils.batch(); - var created = batch(function(snap, prevChild) { + var created = $firebaseUtils.batch(function(snap, prevChild) { var rec = firebaseArray.$$added(snap, prevChild); if( rec ) { firebaseArray.$$process('child_added', rec, prevChild); } }); - var updated = batch(function(snap) { + var updated = $firebaseUtils.batch(function(snap) { var rec = firebaseArray.$getRecord($firebaseUtils.getKey(snap)); if( rec ) { var changed = firebaseArray.$$updated(snap); @@ -640,7 +639,7 @@ } } }); - var moved = batch(function(snap, prevChild) { + var moved = $firebaseUtils.batch(function(snap, prevChild) { var rec = firebaseArray.$getRecord($firebaseUtils.getKey(snap)); if( rec ) { var confirmed = firebaseArray.$$moved(snap, prevChild); @@ -649,7 +648,7 @@ } } }); - var removed = batch(function(snap) { + var removed = $firebaseUtils.batch(function(snap) { var rec = firebaseArray.$getRecord($firebaseUtils.getKey(snap)); if( rec ) { var confirmed = firebaseArray.$$removed(snap); @@ -660,11 +659,11 @@ }); var isResolved = false; - var error = batch(function(err) { + var error = $firebaseUtils.batch(function(err) { _initComplete(err); firebaseArray.$$error(err); }); - var initComplete = batch(_initComplete); + var initComplete = $firebaseUtils.batch(_initComplete); var sync = { destroy: destroy, diff --git a/src/FirebaseObject.js b/src/FirebaseObject.js index d6c84746..aa76171e 100644 --- a/src/FirebaseObject.js +++ b/src/FirebaseObject.js @@ -433,8 +433,7 @@ var isResolved = false; var def = $firebaseUtils.defer(); - var batch = $firebaseUtils.batch(); - var applyUpdate = batch(function(snap) { + var applyUpdate = $firebaseUtils.batch(function(snap) { var changed = firebaseObject.$$updated(snap); if( changed ) { // notifies $watch listeners and @@ -442,8 +441,8 @@ firebaseObject.$$notify(); } }); - var error = batch(firebaseObject.$$error, firebaseObject); - var initComplete = batch(_initComplete); + var error = $firebaseUtils.batch(firebaseObject.$$error, firebaseObject); + var initComplete = $firebaseUtils.batch(_initComplete); var sync = { isDestroyed: false, diff --git a/src/module.js b/src/module.js index 460de19a..1bff256b 100644 --- a/src/module.js +++ b/src/module.js @@ -5,15 +5,6 @@ // services will live. angular.module("firebase", []) //todo use $window - .value("Firebase", exports.Firebase) - - // used in conjunction with firebaseUtils.debounce function, this is the - // amount of time we will wait for additional records before triggering - // Angular's digest scope to dirty check and re-render DOM elements. A - // larger number here significantly improves performance when working with - // big data sets that are frequently changing in the DOM, but delays the - // speed at which each record is rendered in real-time. A number less than - // 100ms will usually be optimal. - .value('firebaseBatchDelay', 50 /* milliseconds */); + .value("Firebase", exports.Firebase); })(window); \ No newline at end of file diff --git a/src/utils.js b/src/utils.js index 4263409c..a4490e42 100644 --- a/src/utils.js +++ b/src/utils.js @@ -23,8 +23,8 @@ } ]) - .factory('$firebaseUtils', ["$q", "$timeout", "firebaseBatchDelay", - function($q, $timeout, firebaseBatchDelay) { + .factory('$firebaseUtils', ["$q", "$timeout", "$rootScope", + function($q, $timeout, $rootScope) { // ES6 style promises polyfill for angular 1.2.x // Copied from angular 1.3.x implementation: https://github.com/angular/angular.js/blob/v1.3.5/src/ng/q.js#L539 @@ -50,88 +50,21 @@ var utils = { /** - * Returns a function which, each time it is invoked, will pause for `wait` - * milliseconds before invoking the original `fn` instance. If another - * request is received in that time, it resets `wait` up until `maxWait` is - * reached. + * Returns a function which, each time it is invoked, will gather up the values until + * the next "tick" in the Angular compiler process. Then they are all run at the same + * time to avoid multiple cycles of the digest loop. Internally, this is done using $evalAsync() * - * Unlike a debounce function, once wait is received, all items that have been - * queued will be invoked (not just once per execution). It is acceptable to use 0, - * which means to batch all synchronously queued items. - * - * The batch function actually returns a wrap function that should be called on each - * method that is to be batched. - * - *
- * var total = 0;
- * var batchWrapper = batch(10, 100);
- * var fn1 = batchWrapper(function(x) { return total += x; });
- * var fn2 = batchWrapper(function() { console.log(total); });
- * fn1(10);
- * fn2();
- * fn1(10);
- * fn2();
- * console.log(total); // 0 (nothing invoked yet)
- * // after 10ms will log "10" and then "20"
- *
- *
- * @param {int} wait number of milliseconds to pause before sending out after each invocation
- * @param {int} maxWait max milliseconds to wait before sending out, defaults to wait * 10 or 100
+ * @param {Function} action
+ * @param {Object} [context]
* @returns {Function}
*/
- batch: function(wait, maxWait) {
- wait = typeof('wait') === 'number'? wait : firebaseBatchDelay;
- if( !maxWait ) { maxWait = wait*10 || 100; }
- var queue = [];
- var start;
- var cancelTimer;
- var runScheduledForNextTick;
-
- // returns `fn` wrapped in a function that queues up each call event to be
- // invoked later inside fo runNow()
- function createBatchFn(fn, context) {
- if( typeof(fn) !== 'function' ) {
- throw new Error('Must provide a function to be batched. Got '+fn);
- }
- return function() {
- var args = Array.prototype.slice.call(arguments, 0);
- queue.push([fn, context, args]);
- resetTimer();
- };
- }
-
- // clears the current wait timer and creates a new one
- // however, if maxWait is exceeded, calls runNow() on the next tick.
- function resetTimer() {
- if( cancelTimer ) {
- cancelTimer();
- cancelTimer = null;
- }
- if( start && Date.now() - start > maxWait ) {
- if(!runScheduledForNextTick){
- runScheduledForNextTick = true;
- utils.compile(runNow);
- }
- }
- else {
- if( !start ) { start = Date.now(); }
- cancelTimer = utils.wait(runNow, wait);
- }
- }
-
- // Clears the queue and invokes all of the functions awaiting notification
- function runNow() {
- cancelTimer = null;
- start = null;
- runScheduledForNextTick = false;
- var copyList = queue.slice(0);
- queue = [];
- angular.forEach(copyList, function(parts) {
- parts[0].apply(parts[1], parts[2]);
+ batch: function(action, context) {
+ return function() {
+ var args = Array.prototype.slice.call(arguments, 0);
+ $rootScope.$evalAsync(function() {
+ action.apply(context, args);
});
- }
-
- return createBatchFn;
+ };
},
/**
@@ -492,7 +425,6 @@
*/
VERSION: '0.0.0',
- batchDelay: firebaseBatchDelay,
allPromises: $q.all.bind($q)
};
diff --git a/tests/unit/utils.spec.js b/tests/unit/utils.spec.js
index a55acf80..74a7e62f 100644
--- a/tests/unit/utils.spec.js
+++ b/tests/unit/utils.spec.js
@@ -46,8 +46,7 @@ describe('$firebaseUtils', function () {
it('should trigger function with arguments', function() {
var spy = jasmine.createSpy();
- var batch = $utils.batch();
- var b = batch(spy);
+ var b = $utils.batch(spy);
b('foo', 'bar');
$timeout.flush();
expect(spy).toHaveBeenCalledWith('foo', 'bar');
@@ -55,8 +54,7 @@ describe('$firebaseUtils', function () {
it('should queue up requests until timeout', function() {
var spy = jasmine.createSpy();
- var batch = $utils.batch();
- var b = batch(spy);
+ var b = $utils.batch(spy);
for(var i=0; i < 4; i++) {
b(i);
}
@@ -70,8 +68,7 @@ describe('$firebaseUtils', function () {
var spy = jasmine.createSpy().and.callFake(function() {
b = this;
});
- var batch = $utils.batch();
- batch(spy, a)();
+ $utils.batch(spy, a)();
$timeout.flush();
expect(spy).toHaveBeenCalled();
expect(b).toBe(a);