feat(change_detection): generate checkNoChanges only in dev mode

This commit is contained in:
vsavkin 2015-07-27 13:16:20 -07:00
parent a2bb81c406
commit 71bb4b3ee5
11 changed files with 68 additions and 31 deletions

View File

@ -1,4 +1,4 @@
import {isPresent} from 'angular2/src/facade/lang';
import {isPresent, BaseException} from 'angular2/src/facade/lang';
import {List, ListWrapper} from 'angular2/src/facade/collection';
import {ChangeDetectorRef} from './change_detector_ref';
import {ChangeDetector} from './interfaces';
@ -38,11 +38,11 @@ export class AbstractChangeDetector implements ChangeDetector {
remove(): void { this.parent.removeChild(this); }
detectChanges(): void { this._detectChanges(false); }
detectChanges(): void { this.runDetectChanges(false); }
checkNoChanges(): void { this._detectChanges(true); }
checkNoChanges(): void { throw new BaseException("Not implemented"); }
_detectChanges(throwOnChange: boolean): void {
runDetectChanges(throwOnChange: boolean): void {
if (this.mode === DETACHED || this.mode === CHECKED) return;
this.detectChangesInRecords(throwOnChange);
@ -67,14 +67,14 @@ export class AbstractChangeDetector implements ChangeDetector {
_detectChangesInLightDomChildren(throwOnChange: boolean): void {
var c = this.lightDomChildren;
for (var i = 0; i < c.length; ++i) {
c[i]._detectChanges(throwOnChange);
c[i].runDetectChanges(throwOnChange);
}
}
_detectChangesInShadowDomChildren(throwOnChange: boolean): void {
var c = this.shadowDomChildren;
for (var i = 0; i < c.length; ++i) {
c[i]._detectChanges(throwOnChange);
c[i].runDetectChanges(throwOnChange);
}
}

View File

@ -35,7 +35,8 @@ export class ChangeDetectorJITGenerator {
_names: CodegenNameUtil;
constructor(public id: string, public changeDetectionStrategy: string,
public records: List<ProtoRecord>, public directiveRecords: List<any>) {
public records: List<ProtoRecord>, public directiveRecords: List<any>,
private generateCheckNoChanges: boolean) {
this._names = new CodegenNameUtil(this.records, this.directiveRecords, 'this._', UTIL);
}
@ -80,6 +81,8 @@ export class ChangeDetectorJITGenerator {
${ALREADY_CHECKED_ACCESSOR} = true;
}
${this._genCheckNoChanges(typeName)}
${typeName}.prototype.callOnAllChangesDone = function() {
${this._genCallOnAllChangesDoneBody()}
}
@ -109,6 +112,7 @@ export class ChangeDetectorJITGenerator {
return new ${typeName}(dispatcher, protos, directiveRecords);
}
`;
return new Function('AbstractChangeDetector', 'ChangeDetectionUtil', 'protos',
'directiveRecords', classDefinition)(
AbstractChangeDetector, ChangeDetectionUtil, this.records, this.directiveRecords);
@ -330,11 +334,23 @@ export class ChangeDetectorJITGenerator {
}
_genThrowOnChangeCheck(oldValue: string, newValue: string): string {
return `
if(throwOnChange) {
${UTIL}.throwOnChange(${CURRENT_PROTO}, ${UTIL}.simpleChange(${oldValue}, ${newValue}));
}
`;
if (this.generateCheckNoChanges) {
return `
if(throwOnChange) {
${UTIL}.throwOnChange(${CURRENT_PROTO}, ${UTIL}.simpleChange(${oldValue}, ${newValue}));
}
`;
} else {
return '';
}
}
_genCheckNoChanges(typeName: string): string {
if (this.generateCheckNoChanges) {
return `${typeName}.prototype.checkNoChanges = function() { this.runDetectChanges(true); }`;
} else {
return '';
}
}
_genAddToChanges(r: ProtoRecord): string {

View File

@ -65,6 +65,8 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
hydrated(): boolean { return this.values[0] !== null; }
checkNoChanges(): void { this.runDetectChanges(true); }
detectChangesInRecords(throwOnChange: boolean) {
if (!this.hydrated()) {
ChangeDetectionUtil.throwDehydrated();

View File

@ -63,5 +63,6 @@ export interface ProtoChangeDetector { instantiate(dispatcher: any): ChangeDetec
export class ChangeDetectorDefinition {
constructor(public id: string, public strategy: string, public variableNames: List<string>,
public bindingRecords: List<BindingRecord>,
public directiveRecords: List<DirectiveRecord>) {}
public directiveRecords: List<DirectiveRecord>,
public generateCheckNoChanges: boolean) {}
}

View File

@ -23,7 +23,8 @@ export class JitProtoChangeDetector implements ProtoChangeDetector {
(b) => { recordBuilder.add(b, definition.variableNames); });
var records = coalesce(recordBuilder.records);
return new ChangeDetectorJITGenerator(definition.id, definition.strategy, records,
this.definition.directiveRecords)
this.definition.directiveRecords,
this.definition.generateCheckNoChanges)
.generate();
}
}

View File

@ -1,7 +1,7 @@
import {Injectable} from 'angular2/di';
import {List, ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
import {isPresent, isBlank, BaseException} from 'angular2/src/facade/lang';
import {isPresent, isBlank, BaseException, assertionsEnabled} from 'angular2/src/facade/lang';
import {reflector} from 'angular2/src/reflection/reflection';
import {
@ -246,7 +246,7 @@ function _getChangeDetectorDefinitions(
var id = `${hostComponentMetadata.id}_${typeString}_${pvWithIndex.index}`;
var variableNames = nestedPvVariableNames[pvWithIndex.index];
return new ChangeDetectorDefinition(id, strategyName, variableNames, bindingRecords,
directiveRecords);
directiveRecords, assertionsEnabled());
});
}

View File

@ -74,10 +74,11 @@ class _CodegenState {
final List<ProtoRecord> _records;
final List<DirectiveRecord> _directiveRecords;
final CodegenNameUtil _names;
final bool _generateCheckNoChanges;
_CodegenState._(this._changeDetectorDefId, this._contextTypeName,
this._changeDetectorTypeName, String changeDetectionStrategy,
List<ProtoRecord> records, List<DirectiveRecord> directiveRecords)
List<ProtoRecord> records, List<DirectiveRecord> directiveRecords, this._generateCheckNoChanges)
: _records = records,
_directiveRecords = directiveRecords,
_names = new CodegenNameUtil(records, directiveRecords, '_', _UTIL),
@ -91,7 +92,7 @@ class _CodegenState {
.forEach((rec) => protoRecords.add(rec, def.variableNames));
var records = coalesce(protoRecords.records);
return new _CodegenState._(def.id, typeName, changeDetectorTypeName,
def.strategy, records, def.directiveRecords);
def.strategy, records, def.directiveRecords, def.generateCheckNoChanges);
}
void _writeToBuf(StringBuffer buf) {
@ -138,6 +139,8 @@ class _CodegenState {
$_ALREADY_CHECKED_ACCESSOR = true;
}
${_genCheckNoChanges()}
void callOnAllChangesDone() {
${_getCallOnAllChangesDoneBody()}
}
@ -393,12 +396,24 @@ class _CodegenState {
}
String _genThrowOnChangeCheck(String oldValue, String newValue) {
return '''
if(throwOnChange) {
$_UTIL.throwOnChange(
$_CURRENT_PROTO, $_UTIL.simpleChange(${oldValue}, ${newValue}));
}
''';
if (this._generateCheckNoChanges) {
return '''
if(throwOnChange) {
$_UTIL.throwOnChange(
$_CURRENT_PROTO, $_UTIL.simpleChange(${oldValue}, ${newValue}));
}
''';
} else {
return "";
}
}
String _genCheckNoChanges() {
if (this._generateCheckNoChanges) {
return 'void checkNoChanges() { this.runDetectChanges(true); }';
} else {
return '';
}
}
String _genAddToChanges(ProtoRecord r) {

View File

@ -23,7 +23,7 @@ export function main() {
beforeEach(() => {
proto = new SpyProtoChangeDetector();
def = new ChangeDetectorDefinition('id', null, [], [], []);
def = new ChangeDetectorDefinition('id', null, [], [], [], true);
});
it("should return a proto change detector when one is available", () => {

View File

@ -69,7 +69,7 @@ export function getDefinition(id: string): TestDefinition {
var bindingRecords = _createBindingRecords(id);
var directiveRecords = [];
let cdDef = new ChangeDetectorDefinition(id, strategy, variableBindings, bindingRecords,
directiveRecords);
directiveRecords, true);
testDef = new TestDefinition(id, cdDef, null);
}
if (isBlank(testDef)) {
@ -107,7 +107,7 @@ class _ExpressionWithLocals {
var bindingRecords = _createBindingRecords(this._expression);
var directiveRecords = [];
return new ChangeDetectorDefinition('(empty id)', strategy, variableBindings, bindingRecords,
directiveRecords);
directiveRecords, true);
}
/**
@ -151,7 +151,7 @@ class _ExpressionWithMode {
directiveRecords = [];
}
return new ChangeDetectorDefinition('(empty id)', this._strategy, variableBindings,
bindingRecords, directiveRecords);
bindingRecords, directiveRecords, true);
}
/**
@ -174,7 +174,7 @@ class _DirectiveUpdating {
var variableBindings = [];
return new ChangeDetectorDefinition('(empty id)', strategy, variableBindings,
this._bindingRecords, this._directiveRecords);
this._bindingRecords, this._directiveRecords, true);
}
static updateA(expression: string, dirRecord): BindingRecord {

View File

@ -91,6 +91,8 @@ class _MyComponent_ChangeDetector0 extends _gen.AbstractChangeDetector {
_alreadyChecked = true;
}
void checkNoChanges() {this.runDetectChanges(true);}
void callOnAllChangesDone() {
dispatcher.notifyOnAllChangesDone();
}

View File

@ -249,7 +249,7 @@ function setUpChangeDetection(changeDetection: ChangeDetection, iterations, obje
var parser = new Parser(new Lexer());
var parentProto = changeDetection.createProtoChangeDetector(
new ChangeDetectorDefinition('parent', null, [], [], []));
new ChangeDetectorDefinition('parent', null, [], [], [], false));
var parentCd = parentProto.instantiate(dispatcher);
var directiveRecord = new DirectiveRecord({directiveIndex: new DirectiveIndex(0, 0)});
@ -277,7 +277,7 @@ function setUpChangeDetection(changeDetection: ChangeDetection, iterations, obje
];
var proto = changeDetection.createProtoChangeDetector(
new ChangeDetectorDefinition("proto", null, [], bindings, [directiveRecord]));
new ChangeDetectorDefinition("proto", null, [], bindings, [directiveRecord], false));
var targetObj = new Obj();
parentCd.hydrate(object, null, new FakeDirectives(targetObj), null);