Skip to content

Commit

Permalink
[BUGFIX] Use WeakMap to store tracked property values. (#18091)
Browse files Browse the repository at this point in the history
[BUGFIX] Use WeakMap to store tracked property values.
  • Loading branch information
rwjblue authored Jun 14, 2019
2 parents 7d86e12 + 1921673 commit 7734bac
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 24 deletions.
25 changes: 13 additions & 12 deletions packages/@ember/-internals/metal/lib/tracked.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { HAS_NATIVE_SYMBOL, isEmberArray, symbol as emberSymbol } from '@ember/-internals/utils';
import { isEmberArray } from '@ember/-internals/utils';
import { EMBER_NATIVE_DECORATOR_SUPPORT } from '@ember/canary-features';
import { assert } from '@ember/debug';
import { DEBUG } from '@glimmer/env';
Expand All @@ -9,10 +9,6 @@ import { markObjectAsDirty, tagForProperty, update } from './tags';

type Option<T> = T | null;

// For some reason TS can't infer that these two functions are compatible-ish,
// so we need to corece the type
let symbol = (HAS_NATIVE_SYMBOL ? Symbol : emberSymbol) as (debugKey: string) => string;

/**
An object that that tracks @tracked properties that were consumed.
Expand Down Expand Up @@ -192,7 +188,8 @@ function descriptorForField([_target, key, desc]: [
);

let initializer = desc ? desc.initializer : undefined;
let secretKey = symbol(key);
let values = new WeakMap();
let hasInitializer = typeof initializer === 'function';

return {
enumerable: true,
Expand All @@ -203,26 +200,30 @@ function descriptorForField([_target, key, desc]: [

if (CURRENT_TRACKER) CURRENT_TRACKER.add(propertyTag);

let value;

// If the field has never been initialized, we should initialize it
if (!(secretKey in this)) {
this[secretKey] = typeof initializer === 'function' ? initializer.call(this) : undefined;
}
if (hasInitializer && !values.has(this)) {
value = initializer.call(this);

let value = this[secretKey];
values.set(this, value);
} else {
value = values.get(this);
}

// Add the tag of the returned value if it is an array, since arrays
// should always cause updates if they are consumed and then changed
if (Array.isArray(value) || isEmberArray(value)) {
update(propertyTag, tagForProperty(value, '[]'));
}

return this[secretKey];
return value;
},

set(newValue: any): void {
markObjectAsDirty(this, key);

this[secretKey] = newValue;
values.set(this, newValue);

if (propertyDidChange !== null) {
propertyDidChange();
Expand Down
4 changes: 2 additions & 2 deletions packages/@ember/controller/tests/controller_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,10 @@ moduleFor(
assert.expect(3);
expectNoDeprecation();

let controller = Controller.extend({
let controller = Controller.create({
content: 'foo-bar',
model: 'blammo',
}).create();
});

assert.equal(get(controller, 'content'), 'foo-bar');
assert.equal(get(controller, 'model'), 'blammo');
Expand Down
25 changes: 15 additions & 10 deletions packages/ember/tests/routing/decoupled_basic_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,9 @@ moduleFor(
this.add(
'controller:homepage',
Controller.extend({
model: {
home: 'Comes from homepage',
init() {
this._super(...arguments);
this.model = { home: 'Comes from homepage' };
},
})
);
Expand All @@ -183,16 +184,18 @@ moduleFor(
this.add(
'controller:foo',
Controller.extend({
model: {
home: 'Comes from foo',
init() {
this._super(...arguments);
this.model = { home: 'Comes from foo' };
},
})
);
this.add(
'controller:homepage',
Controller.extend({
model: {
home: 'Comes from homepage',
init() {
this._super(...arguments);
this.model = { home: 'Comes from homepage' };
},
})
);
Expand Down Expand Up @@ -220,8 +223,9 @@ moduleFor(
this.add(
'controller:home',
Controller.extend({
model: {
home: 'Comes from home.',
init() {
this._super(...arguments);
this.model = { home: 'Comes from home.' };
},
})
);
Expand All @@ -241,8 +245,9 @@ moduleFor(
this.add(
'controller:home',
Controller.extend({
model: {
home: 'YES I AM HOME',
init() {
this._super(...arguments);
this.model = { home: 'YES I AM HOME' };
},
})
);
Expand Down

0 comments on commit 7734bac

Please sign in to comment.