fix(change detection): preserve memoized results from pure functions

This commit is contained in:
Yegor Jbanov 2015-06-17 12:56:11 -07:00
parent b0e2ebda70
commit 5beaf6d735
5 changed files with 23 additions and 11 deletions

View File

@ -291,7 +291,7 @@ export class ChangeDetectorJITGenerator {
if (r.isPureFunction()) { if (r.isPureFunction()) {
var condition = r.args.map((a) => this._changeNames[a]).join(" || "); var condition = r.args.map((a) => this._changeNames[a]).join(" || ");
return `if (${condition}) { ${check} }`; return `if (${condition}) { ${check} } else { ${newValue} = ${oldValue}; }`;
} else { } else {
return check; return check;
} }

View File

@ -69,12 +69,11 @@ var _rootBindings = [bind(Reflector).toValue(reflector), TestabilityRegistry];
function _injectorBindings(appComponentType): List<Type | Binding | List<any>> { function _injectorBindings(appComponentType): List<Type | Binding | List<any>> {
var bestChangeDetection: Type = DynamicChangeDetection; var bestChangeDetection: Type = DynamicChangeDetection;
// Re-enable once all e2e tests pass if (PreGeneratedChangeDetection.isSupported()) {
// if (PreGeneratedChangeDetection.isSupported()) { bestChangeDetection = PreGeneratedChangeDetection;
// bestChangeDetection = PreGeneratedChangeDetection; } else if (JitChangeDetection.isSupported()) {
//} else if (JitChangeDetection.isSupported()) { bestChangeDetection = JitChangeDetection;
// bestChangeDetection = JitChangeDetection; }
//}
return [ return [
bind(DOCUMENT_TOKEN) bind(DOCUMENT_TOKEN)
.toValue(DOM.defaultDoc()), .toValue(DOM.defaultDoc()),

View File

@ -352,7 +352,7 @@ class _CodegenState {
if (r.isPureFunction()) { if (r.isPureFunction()) {
// Add an "if changed guard" // Add an "if changed guard"
var condition = r.args.map((a) => _changeNames[a]).join(' || '); var condition = r.args.map((a) => _changeNames[a]).join(' || ');
return 'if ($condition) { $check }'; return 'if ($condition) { $check } else { $newValue = $oldValue; }';
} else { } else {
return check; return check;
} }

View File

@ -303,5 +303,6 @@ var _availableDefinitions = [
'address?.toString()', 'address?.toString()',
'sayHi("Jim")', 'sayHi("Jim")',
'a()(99)', 'a()(99)',
'a.sayHi("Jim")' 'a.sayHi("Jim")',
'passThrough([12])'
]; ];

View File

@ -54,8 +54,8 @@ const _DEFAULT_CONTEXT = CONST_EXPR(new Object());
/** /**
* Tests in this spec run against three different implementations of `AbstractChangeDetector`, * Tests in this spec run against three different implementations of `AbstractChangeDetector`,
* `dynamic` (which use reflection to inspect objects), `JIT` (which are generated only for * `dynamic` (which use reflection to inspect objects), `JIT` (which are generated only for
* Javascript at runtime using `eval` to avoid the need for reflection) and `Pregen` (which are * Javascript at runtime using `eval`) and `Pregen` (which are generated only for Dart prior
* generated only for Dart prior to app deploy to avoid the need for reflection). * to app deploy to avoid the need for reflection).
* *
* Pre-generated classes require knowledge of the shape of the change detector at the time of Dart * Pre-generated classes require knowledge of the shape of the change detector at the time of Dart
* transformation, so in these tests we abstract a `ChangeDetectorDefinition` out into the * transformation, so in these tests we abstract a `ChangeDetectorDefinition` out into the
@ -304,6 +304,16 @@ export function main() {
expect(val.dispatcher.log).toEqual(['propName=BvalueA']); expect(val.dispatcher.log).toEqual(['propName=BvalueA']);
}); });
describe('pure functions', () => {
it('should preserve memoized result', () => {
var person = new Person('bob');
var val = _createChangeDetector('passThrough([12])', person);
val.changeDetector.detectChanges();
val.changeDetector.detectChanges();
expect(val.dispatcher.loggedValues).toEqual([[12]]);
});
});
describe('change notification', () => { describe('change notification', () => {
describe('simple checks', () => { describe('simple checks', () => {
it('should pass a change record to the dispatcher', () => { it('should pass a change record to the dispatcher', () => {
@ -948,6 +958,8 @@ class Person {
sayHi(m) { return `Hi, ${m}`; } sayHi(m) { return `Hi, ${m}`; }
passThrough(val) { return val; }
toString(): string { toString(): string {
var address = this.address == null ? '' : ' address=' + this.address.toString(); var address = this.address == null ? '' : ' address=' + this.address.toString();