Skip to content

Commit

Permalink
Merge pull request #19670 from nlfurniss/remove-volatile
Browse files Browse the repository at this point in the history
Remove .volatile()
  • Loading branch information
mixonic authored Jul 31, 2021
2 parents a1760eb + 89760ae commit c3a7fd9
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 184 deletions.
88 changes: 4 additions & 84 deletions packages/@ember/-internals/metal/lib/computed.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Meta, meta as metaFor } from '@ember/-internals/meta';
import { inspect, toString } from '@ember/-internals/utils';
import { assert, deprecate, warn } from '@ember/debug';
import { assert, warn } from '@ember/debug';
import EmberError from '@ember/error';
import { isDestroyed } from '@glimmer/destroyable';
import { DEBUG } from '@glimmer/env';
Expand Down Expand Up @@ -249,7 +249,6 @@ function noop(): void {}
@public
*/
export class ComputedProperty extends ComputedDescriptor {
_volatile = false;
_readOnly = false;
protected _hasConfig = false;

Expand Down Expand Up @@ -370,10 +369,6 @@ export class ComputedProperty extends ComputedDescriptor {
}

get(obj: object, keyName: string): any {
if (this._volatile) {
return this._getter!.call(obj, keyName);
}

let meta = metaFor(obj);
let tagMeta = tagMetaFor(obj);

Expand Down Expand Up @@ -435,10 +430,6 @@ export class ComputedProperty extends ComputedDescriptor {
this._setter !== undefined
);

if (this._volatile) {
return this.volatileSet(obj, keyName, value);
}

let meta = metaFor(obj);

// ensure two way binding works when the component has defined a computed
Expand Down Expand Up @@ -500,10 +491,6 @@ export class ComputedProperty extends ComputedDescriptor {
throw new EmberError(`Cannot set read-only property "${keyName}" on object: ${inspect(obj)}`);
}

volatileSet(obj: object, keyName: string, value: any): any {
return this._setter!.call(obj, keyName, value);
}

_set(obj: object, keyName: string, value: unknown, meta: Meta): any {
let hadCachedValue = meta.revisionFor(keyName) !== undefined;
let cachedValue = meta.valueFor(keyName);
Expand Down Expand Up @@ -533,11 +520,9 @@ export class ComputedProperty extends ComputedDescriptor {

/* called before property is overridden */
teardown(obj: object, keyName: string, meta: Meta): void {
if (!this._volatile) {
if (meta.revisionFor(keyName) !== undefined) {
meta.setRevisionFor(keyName, undefined);
meta.setValueFor(keyName, undefined);
}
if (meta.revisionFor(keyName) !== undefined) {
meta.setRevisionFor(keyName, undefined);
meta.setValueFor(keyName, undefined);
}

super.teardown(obj, keyName, meta);
Expand All @@ -546,10 +531,6 @@ export class ComputedProperty extends ComputedDescriptor {

class AutoComputedProperty extends ComputedProperty {
get(obj: object, keyName: string): any {
if (this._volatile) {
return this._getter!.call(obj, keyName);
}

let meta = metaFor(obj);
let tagMeta = tagMetaFor(obj);

Expand Down Expand Up @@ -648,67 +629,6 @@ class ComputedDecoratorImpl extends Function {
return this;
}

/**
Call on a computed property to set it into non-cached mode. When in this
mode the computed property will not automatically cache the return value.
It also does not automatically fire any change events. You must manually notify
any changes if you want to observe this property.
Dependency keys have no effect on volatile properties as they are for cache
invalidation and notification when cached value is invalidated.
Example:
```javascript
import { computed } from '@ember/object';
class CallCounter {
_calledCount = 0;
@computed().volatile()
get calledCount() {
return this._calledCount++;
}
}
```
Classic Class Example:
```javascript
import EmberObject, { computed } from '@ember/object';
let CallCounter = EmberObject.extend({
_calledCount: 0,
value: computed(function() {
return this._calledCount++;
}).volatile()
});
```
@method volatile
@deprecated
@return {ComputedProperty} this
@chainable
@public
*/
volatile(this: Decorator) {
deprecate(
'Setting a computed property as volatile has been deprecated. Instead, consider using a native getter with native class syntax.',
false,
{
id: 'computed-property.volatile',
until: '4.0.0',
url: 'https://deprecations.emberjs.com/v3.x#toc_computed-property-volatile',
for: 'ember-source',
since: {
enabled: '3.9.0-beta.1',
},
}
);
(descriptorForDecorator(this) as ComputedProperty)._volatile = true;
return this;
}

/**
In some cases, you may want to annotate computed properties with additional
metadata about how they function or what values they operate on. For example,
Expand Down
1 change: 0 additions & 1 deletion packages/@ember/-internals/metal/lib/mixin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,6 @@ function giveDecoratorSuper(
]);

newProperty._readOnly = property._readOnly;
newProperty._volatile = property._volatile;
newProperty._meta = property._meta;
newProperty.enumerable = property.enumerable;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,120 +298,83 @@ moduleFor(
beforeEach() {
lookup = context.lookup = {};

expectDeprecation(() => {
object = ObservableObject.extend({
computed: computed({
get() {
this.computedCalls.push('getter-called');
return 'computed';
},
set(key, value) {
this.computedCalls.push(value);
},
}).volatile(),

computedCached: computed({
get() {
this.computedCachedCalls.push('getter-called');
return 'computedCached';
},
set: function (key, value) {
this.computedCachedCalls.push(value);
},
}),
object = ObservableObject.extend({
computed: computed({
get() {
this.computedCalls.push('getter-called');
return 'computed';
},
set(key, value) {
this.computedCalls.push(value);
},
}),

dependent: computed('changer', {
get() {
this.dependentCalls.push('getter-called');
return 'dependent';
},
set(key, value) {
this.dependentCalls.push(value);
},
}).volatile(),
dependentFront: computed('changer', {
get() {
this.dependentFrontCalls.push('getter-called');
return 'dependentFront';
},
set(key, value) {
this.dependentFrontCalls.push(value);
},
}).volatile(),
dependentCached: computed('changer', {
get() {
this.dependentCachedCalls.push('getter-called!');
return 'dependentCached';
},
set(key, value) {
this.dependentCachedCalls.push(value);
},
}),
dependent: computed('changer', {
get() {
this.dependentCalls.push('getter-called');
return 'dependent';
},
set(key, value) {
this.dependentCalls.push(value);
},
}),

inc: computed('changer', function () {
return this.incCallCount++;
}),
inc: computed('changer', function () {
return this.incCallCount++;
}),

nestedInc: computed('inc', function () {
get(this, 'inc');
return this.nestedIncCallCount++;
}),
nestedInc: computed('inc', function () {
get(this, 'inc');
return this.nestedIncCallCount++;
}),

isOn: computed('state', {
get() {
return this.get('state') === 'on';
},
set() {
this.set('state', 'on');
return this.get('state') === 'on';
},
}).volatile(),

isOff: computed('state', {
get() {
return this.get('state') === 'off';
},
set() {
this.set('state', 'off');
return this.get('state') === 'off';
},
}).volatile(),
}).create({
computedCalls: [],
computedCachedCalls: [],
changer: 'foo',
dependentCalls: [],
dependentFrontCalls: [],
dependentCachedCalls: [],
incCallCount: 0,
nestedIncCallCount: 0,
state: 'on',
});
isOn: computed('state', {
get() {
return this.get('state') === 'on';
},
set() {
this.set('state', 'on');
return this.get('state') === 'on';
},
}),

isOff: computed('state', {
get() {
return this.get('state') === 'off';
},
set() {
this.set('state', 'off');
return this.get('state') === 'off';
},
}),
}).create({
computedCalls: [],
changer: 'foo',
dependentCalls: [],
incCallCount: 0,
nestedIncCallCount: 0,
state: 'on',
});
}

['@test getting values should call function return value'](assert) {
// get each property twice. Verify return.
let keys = w('computed computedCached dependent dependentFront dependentCached');
let keys = w('computed dependent');

keys.forEach(function (key) {
assert.equal(object.get(key), key, `Try #1: object.get(${key}) should run function`);
assert.equal(object.get(key), key, `Try #2: object.get(${key}) should run function`);
});

// verify each call count. cached should only be called once
w('computedCalls dependentFrontCalls dependentCalls').forEach((key) => {
assert.equal(object[key].length, 2, `non-cached property ${key} should be called 2x`);
});

w('computedCachedCalls dependentCachedCalls').forEach((key) => {
// verify each call count. cached should only be called once
w('computedCalls dependentCalls').forEach((key) => {
assert.equal(object[key].length, 1, `non-cached property ${key} should be called 1x`);
});
}

['@test setting values should call function return value'](assert) {
// get each property twice. Verify return.
let keys = w('computed dependent dependentFront computedCached dependentCached');
let keys = w('computed dependent');
let values = w('value1 value2');

keys.forEach((key) => {
Expand Down Expand Up @@ -459,13 +422,13 @@ moduleFor(

['@test notify change should clear cache'](assert) {
// call get several times to collect call count
object.get('computedCached'); // should run func
object.get('computedCached'); // should not run func
object.get('computed'); // should run func
object.get('computed'); // should not run func

object.notifyPropertyChange('computedCached');
object.notifyPropertyChange('computed');

object.get('computedCached'); // should run again
assert.equal(object.computedCachedCalls.length, 2, 'should have invoked method 2x');
object.get('computed'); // should run again
assert.equal(object.computedCalls.length, 2, 'should have invoked method 2x');
}

['@test change dependent should clear cache'](assert) {
Expand Down
1 change: 0 additions & 1 deletion tests/docs/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,6 @@ module.exports = {
'validationCache',
'value',
'visit',
'volatile',
'w',
'wait',
'waitForDOMReady',
Expand Down

0 comments on commit c3a7fd9

Please sign in to comment.