diff --git a/modules/change_detection/src/change_detection_jit_generator.es6 b/modules/change_detection/src/change_detection_jit_generator.es6 index 8b97e22f0d..31df528142 100644 --- a/modules/change_detection/src/change_detection_jit_generator.es6 +++ b/modules/change_detection/src/change_detection_jit_generator.es6 @@ -43,7 +43,7 @@ import { * var address0; * var city1; * var change; - * var changes = []; + * var changes = null; * var temp; * var context = this.context; * @@ -60,14 +60,15 @@ import { * * city1 = address0.city; * if (city1 !== this.city1) { - * changes.push(ChangeDetectionUtil.simpleChangeRecord(this.protos[1].bindingMemento, this.city1, city1)); + * changes = ChangeDetectionUtil.addRecord(changes, + * ChangeDetectionUtil.simpleChangeRecord(this.protos[1].bindingMemento, this.city1, city1)); * this.city1 = city1; * } * * if (changes.length > 0) { * if(throwOnChange) ChangeDetectionUtil.throwOnChange(this.protos[1], changes[0]); * this.dispatcher.onRecordChange('address.city', changes); - * changes = []; + * changes = null; * } * } * @@ -144,7 +145,7 @@ ${localDefinitions} ${changeDefinitions} var ${TEMP_LOCAL}; var ${CHANGE_LOCAL}; -var ${CHANGES_LOCAL} = []; +var ${CHANGES_LOCAL} = null; context = this.context; ${records} @@ -153,10 +154,10 @@ ${records} function notifyTemplate(index:number):string{ return ` -if (${CHANGES_LOCAL}.length > 0) { +if (${CHANGES_LOCAL} && ${CHANGES_LOCAL}.length > 0) { if(throwOnChange) ${UTIL}.throwOnChange(${PROTOS_ACCESSOR}[${index}], ${CHANGES_LOCAL}[0]); ${DISPATCHER_ACCESSOR}.onRecordChange(${PROTOS_ACCESSOR}[${index}].groupMemento, ${CHANGES_LOCAL}); - ${CHANGES_LOCAL} = []; + ${CHANGES_LOCAL} = null; } `; } @@ -166,7 +167,8 @@ function structuralCheckTemplate(selfIndex:number, field:string, context:string, return ` ${CHANGE_LOCAL} = ${UTIL}.structuralCheck(${field}, ${context}); if (${CHANGE_LOCAL}) { - ${CHANGES_LOCAL}.push(${UTIL}.changeRecord(${PROTOS_ACCESSOR}[${selfIndex}].bindingMemento, ${CHANGE_LOCAL})); + ${CHANGES_LOCAL} = ${UTIL}.addRecord(${CHANGES_LOCAL}, + ${UTIL}.changeRecord(${PROTOS_ACCESSOR}[${selfIndex}].bindingMemento, ${CHANGE_LOCAL})); ${field} = ${CHANGE_LOCAL}.currentValue; } ${notify} @@ -222,7 +224,8 @@ if (${cond}) { } function addSimpleChangeRecordTemplate(protoIndex:number, oldValue:string, newValue:string) { - return `${CHANGES_LOCAL}.push(${UTIL}.simpleChangeRecord(${PROTOS_ACCESSOR}[${protoIndex}].bindingMemento, ${oldValue}, ${newValue}));`; + return `${CHANGES_LOCAL} = ${UTIL}.addRecord(${CHANGES_LOCAL}, + ${UTIL}.simpleChangeRecord(${PROTOS_ACCESSOR}[${protoIndex}].bindingMemento, ${oldValue}, ${newValue}));`; } diff --git a/modules/change_detection/src/change_detection_util.js b/modules/change_detection/src/change_detection_util.js index c9a0ecb96c..9cc8443476 100644 --- a/modules/change_detection/src/change_detection_util.js +++ b/modules/change_detection/src/change_detection_util.js @@ -19,6 +19,72 @@ export class SimpleChange { } } +var _simpleChangesIndex = 0; +var _simpleChanges = [ + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null) +] + +var _changeRecordsIndex = 0; +var _changeRecords = [ + new ChangeRecord(null, null), + new ChangeRecord(null, null), + new ChangeRecord(null, null), + new ChangeRecord(null, null), + new ChangeRecord(null, null), + new ChangeRecord(null, null), + new ChangeRecord(null, null), + new ChangeRecord(null, null), + new ChangeRecord(null, null), + new ChangeRecord(null, null), + new ChangeRecord(null, null), + new ChangeRecord(null, null), + new ChangeRecord(null, null), + new ChangeRecord(null, null), + new ChangeRecord(null, null), + new ChangeRecord(null, null), + new ChangeRecord(null, null), + new ChangeRecord(null, null), + new ChangeRecord(null, null), + new ChangeRecord(null, null) +] + +function _simpleChange(previousValue, currentValue) { + var index = _simpleChangesIndex++ % 20; + var s = _simpleChanges[index]; + s.previousValue = previousValue; + s.currentValue = currentValue; + return s; +} + +function _changeRecord(bindingMemento, change) { + var index = _changeRecordsIndex++ % 20; + var s = _changeRecords[index]; + s.bindingMemento = bindingMemento; + s.change = change; + return s; +} + +var _singleElementList = [null]; + export class ChangeDetectionUtil { static unitialized() { return uninitialized; @@ -128,11 +194,29 @@ export class ChangeDetectionUtil { throw new ExpressionChangedAfterItHasBeenChecked(proto, change); } + static simpleChange(previousValue:any, currentValue:any):SimpleChange { + return _simpleChange(previousValue, currentValue); + } + static changeRecord(memento:any, change:any):ChangeRecord { - return new ChangeRecord(memento, change); + return _changeRecord(memento, change); } static simpleChangeRecord(memento:any, previousValue:any, currentValue:any):ChangeRecord { - return new ChangeRecord(memento, new SimpleChange(previousValue, currentValue)); + return _changeRecord(memento, _simpleChange(previousValue, currentValue)); } -} + + static addRecord(updatedRecords:List, changeRecord:ChangeRecord):List { + if (isBlank(updatedRecords)) { + updatedRecords = _singleElementList; + updatedRecords[0] = changeRecord; + + } else if (updatedRecords === _singleElementList) { + updatedRecords = [_singleElementList[0], changeRecord]; + + } else { + ListWrapper.push(updatedRecords, changeRecord); + } + return updatedRecords; + } +} \ No newline at end of file diff --git a/modules/change_detection/src/dynamic_change_detector.js b/modules/change_detection/src/dynamic_change_detector.js index 2223b10dc1..0039f5e99f 100644 --- a/modules/change_detection/src/dynamic_change_detector.js +++ b/modules/change_detection/src/dynamic_change_detector.js @@ -62,7 +62,8 @@ export class DynamicChangeDetector extends AbstractChangeDetector { if (isPresent(change)) { currentGroup = proto.groupMemento; - updatedRecords = this._addRecord(updatedRecords, proto, change); + var record = ChangeDetectionUtil.changeRecord(proto.bindingMemento, change); + updatedRecords = ChangeDetectionUtil.addRecord(updatedRecords, record); } if (proto.lastInGroup && isPresent(updatedRecords)) { @@ -100,7 +101,7 @@ export class DynamicChangeDetector extends AbstractChangeDetector { this._setChanged(proto, true); if (proto.lastInBinding) { - return new SimpleChange(prevValue, currValue); + return ChangeDetectionUtil.simpleChange(prevValue, currValue); } else { return null; } @@ -164,22 +165,6 @@ export class DynamicChangeDetector extends AbstractChangeDetector { return change; } - _addRecord(updatedRecords:List, proto:ProtoRecord, change):List { - // we can use a pool of change records not to create extra garbage - var record = ChangeDetectionUtil.changeRecord(proto.bindingMemento, change); - if (isBlank(updatedRecords)) { - updatedRecords = _singleElementList; - updatedRecords[0] = record; - - } else if (updatedRecords === _singleElementList) { - updatedRecords = [_singleElementList[0], record]; - - } else { - ListWrapper.push(updatedRecords, record); - } - return updatedRecords; - } - _readContext(proto:ProtoRecord) { return this.values[proto.contextIndex]; } diff --git a/modules/change_detection/test/change_detection_spec.js b/modules/change_detection/test/change_detection_spec.js index 195aa00ce8..30460d6590 100644 --- a/modules/change_detection/test/change_detection_spec.js +++ b/modules/change_detection/test/change_detection_spec.js @@ -59,6 +59,10 @@ export function main() { expect(dispatcher.log).toEqual(['name=misko']); dispatcher.clear(); + cd.detectChanges(); + expect(dispatcher.log).toEqual([]); + dispatcher.clear(); + person.name = "Misko"; cd.detectChanges(); expect(dispatcher.log).toEqual(['name=Misko']);