From 7cdeefc69bd1d62e068a5052c99ad0da2c8d91f6 Mon Sep 17 00:00:00 2001 From: Edward Faulkner Date: Tue, 21 Oct 2014 15:11:52 -0400 Subject: [PATCH] Make computed.sort generate an answer immediately This is a followup to pull #9356 that gives nicer timing. It extends the arrayComputed protocol with a `flushedChanges` callback so that implementations like `computed.sort` can confidently do batched operations without waiting a whole run loop. --- packages/ember-runtime/lib/computed/reduce_computed.js | 8 ++++++-- .../ember-runtime/lib/computed/reduce_computed_macros.js | 5 ++++- .../tests/computed/reduce_computed_macros_test.js | 5 +++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/ember-runtime/lib/computed/reduce_computed.js b/packages/ember-runtime/lib/computed/reduce_computed.js index 62a4a1df944..8e2468949b2 100644 --- a/packages/ember-runtime/lib/computed/reduce_computed.js +++ b/packages/ember-runtime/lib/computed/reduce_computed.js @@ -277,6 +277,7 @@ DependentArraysObserver.prototype = { this.setValue(removedItem.call( this.instanceMeta.context, this.getValue(), item, changeMeta, this.instanceMeta.sugarMeta)); } + this.callbacks.flushedChanges.call(this.instanceMeta.context, this.getValue(), this.instanceMeta.sugarMeta); }, dependentArrayDidChange: function (dependentArray, index, removedCount, addedCount) { @@ -308,7 +309,7 @@ DependentArraysObserver.prototype = { this.setValue(addedItem.call( this.instanceMeta.context, this.getValue(), item, changeMeta, this.instanceMeta.sugarMeta)); }, this); - + this.callbacks.flushedChanges.call(this.instanceMeta.context, this.getValue(), this.instanceMeta.sugarMeta); this.trackAdd(dependentKey, normalizedIndex, observerContexts); }, @@ -352,6 +353,7 @@ DependentArraysObserver.prototype = { } this.changedItems = {}; + this.callbacks.flushedChanges.call(this.instanceMeta.context, this.getValue(), this.instanceMeta.sugarMeta); } }; @@ -388,6 +390,7 @@ function addItems(dependentArray, callbacks, cp, propertyName, meta) { meta.setValue( callbacks.addedItem.call( this, meta.getValue(), item, new ChangeMeta(dependentArray, item, index, propertyName, cp, dependentArray.length), meta.sugarMeta)); }, this); + callbacks.flushedChanges.call(this, meta.getValue(), meta.sugarMeta); } function reset(cp, propertyName) { @@ -562,7 +565,8 @@ ReduceComputedProperty.prototype._callbacks = function () { this.callbacks = { removedItem: options.removedItem || defaultCallback, - addedItem: options.addedItem || defaultCallback + addedItem: options.addedItem || defaultCallback, + flushedChanges: options.flushedChanges || defaultCallback }; } diff --git a/packages/ember-runtime/lib/computed/reduce_computed_macros.js b/packages/ember-runtime/lib/computed/reduce_computed_macros.js index 979a3e2fa88..7bea20e6e5d 100644 --- a/packages/ember-runtime/lib/computed/reduce_computed_macros.js +++ b/packages/ember-runtime/lib/computed/reduce_computed_macros.js @@ -715,7 +715,6 @@ function customSort(itemsKey, comparator) { }; instanceMeta.insertLater = function(item) { this.waitingInsertions.push(item); - run.once(this, 'insertWaiting'); }; }, @@ -727,6 +726,10 @@ function customSort(itemsKey, comparator) { removedItem: function (array, item, changeMeta, instanceMeta) { array.removeObject(item); return array; + }, + + flushedChanges: function(array, instanceMeta) { + instanceMeta.insertWaiting(); } }); } diff --git a/packages/ember-runtime/tests/computed/reduce_computed_macros_test.js b/packages/ember-runtime/tests/computed/reduce_computed_macros_test.js index 6addf78fae1..13d575b0820 100644 --- a/packages/ember-runtime/tests/computed/reduce_computed_macros_test.js +++ b/packages/ember-runtime/tests/computed/reduce_computed_macros_test.js @@ -1191,16 +1191,17 @@ test("sorts correctly with a user-provided comparator when there are concurrent var sorted; run(function() { sorted = obj.get('customSortedItems'); + deepEqual(sorted.mapBy('name'), ['A', 'B', 'C', 'D'], "initial"); }); - deepEqual(sorted.mapBy('name'), ['A', 'B', 'C', 'D'], "initial"); + run(function() { Ember.changeProperties(function(){ obj.get('items').objectAt(1).set('count', 5); obj.get('items').objectAt(2).set('count', 6); }); sorted = obj.get('customSortedItems'); + deepEqual(sorted.mapBy('name'), ['A', 'D', 'B', 'C'], "final"); }); - deepEqual(sorted.mapBy('name'), ['A', 'D', 'B', 'C'], "final"); });