From 7bbbd6aeb7d51ea2ab3abb14066d110cb3c5226c Mon Sep 17 00:00:00 2001 From: Standa Opichal Date: Thu, 18 Sep 2014 15:26:07 +0200 Subject: [PATCH] Get firstObject/lastObject notifications only when cached Basically the contents of https://gist.github.com/mmun/877bad33158578a8609b --- packages/ember-runtime/lib/mixins/array.js | 27 +++++++++++-------- .../tests/suites/mutable_array/replace.js | 17 ++++++++++++ 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/packages/ember-runtime/lib/mixins/array.js b/packages/ember-runtime/lib/mixins/array.js index 9830280f5d4..e441d3eec19 100644 --- a/packages/ember-runtime/lib/mixins/array.js +++ b/packages/ember-runtime/lib/mixins/array.js @@ -10,6 +10,7 @@ import Ember from 'ember-metal/core'; // ES6TODO: Ember.A import symbol from 'ember-metal/symbol'; import { get } from 'ember-metal/property_get'; +import { peekMeta } from 'ember-metal/utils'; import { computed, cacheFor @@ -517,18 +518,22 @@ export default Mixin.create(Enumerable, { sendEvent(this, '@array:change', [this, startIdx, removeAmt, addAmt]); + // firstObject/lastObject change notifications + // The call to objectAt() should only occur if there is a cached value var length = get(this, 'length'); - var cachedFirst = cacheFor(this, 'firstObject'); - var cachedLast = cacheFor(this, 'lastObject'); - - if (objectAt(this, 0) !== cachedFirst) { - propertyWillChange(this, 'firstObject'); - propertyDidChange(this, 'firstObject'); - } - - if (objectAt(this, length - 1) !== cachedLast) { - propertyWillChange(this, 'lastObject'); - propertyDidChange(this, 'lastObject'); + var meta = peekMeta(this); + var cache = meta && meta.readableCache(); + if (cache) { + if (cache['firstObject'] !== undefined && + this.objectAt(0) !== cacheFor(this, 'firstObject')) { + propertyWillChange(this, 'firstObject'); + propertyDidChange(this, 'firstObject'); + } + if (cache['lastObject'] !== undefined && + this.objectAt(length - 1) !== cacheFor(this, 'lastObject')) { + propertyWillChange(this, 'lastObject'); + propertyDidChange(this, 'lastObject'); + } } return this; diff --git a/packages/ember-runtime/tests/suites/mutable_array/replace.js b/packages/ember-runtime/tests/suites/mutable_array/replace.js index 7b8793c7232..daf993b8f2e 100644 --- a/packages/ember-runtime/tests/suites/mutable_array/replace.js +++ b/packages/ember-runtime/tests/suites/mutable_array/replace.js @@ -22,6 +22,23 @@ suite.test('[].replace(0,0,\'X\') => [\'X\'] + notify', function() { equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); }); +suite.test('[].replace(0,0,"X") => ["X"] + avoid calling objectAt and notifying fistObject/lastObject when not in cache', function() { + var obj, exp, observer; + var called = 0; + exp = this.newFixture(1); + obj = this.newObject([]); + obj.objectAt = function() { + called++; + }; + observer = this.newObserver(obj, 'firstObject', 'lastObject'); + + obj.replace(0, 0, exp); + + equal(called, 0, 'should NOT have called objectAt upon replace when firstObject/lastObject are not cached'); + equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject since not cached'); + equal(observer.validate('lastObject'), false, 'should NOT have notified lastObject since not cached'); +}); + suite.test('[A,B,C,D].replace(1,2,X) => [A,X,D] + notify', function() { var obj, observer, before, replace, after;