perf(change_detection): use object pools not to create unnecessary garbage
This commit is contained in:
parent
62f08d38db
commit
db0f0c462b
|
@ -43,7 +43,7 @@ import {
|
||||||
* var address0;
|
* var address0;
|
||||||
* var city1;
|
* var city1;
|
||||||
* var change;
|
* var change;
|
||||||
* var changes = [];
|
* var changes = null;
|
||||||
* var temp;
|
* var temp;
|
||||||
* var context = this.context;
|
* var context = this.context;
|
||||||
*
|
*
|
||||||
|
@ -60,14 +60,15 @@ import {
|
||||||
*
|
*
|
||||||
* city1 = address0.city;
|
* city1 = address0.city;
|
||||||
* if (city1 !== this.city1) {
|
* 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;
|
* this.city1 = city1;
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* if (changes.length > 0) {
|
* if (changes.length > 0) {
|
||||||
* if(throwOnChange) ChangeDetectionUtil.throwOnChange(this.protos[1], changes[0]);
|
* if(throwOnChange) ChangeDetectionUtil.throwOnChange(this.protos[1], changes[0]);
|
||||||
* this.dispatcher.onRecordChange('address.city', changes);
|
* this.dispatcher.onRecordChange('address.city', changes);
|
||||||
* changes = [];
|
* changes = null;
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
|
@ -144,7 +145,7 @@ ${localDefinitions}
|
||||||
${changeDefinitions}
|
${changeDefinitions}
|
||||||
var ${TEMP_LOCAL};
|
var ${TEMP_LOCAL};
|
||||||
var ${CHANGE_LOCAL};
|
var ${CHANGE_LOCAL};
|
||||||
var ${CHANGES_LOCAL} = [];
|
var ${CHANGES_LOCAL} = null;
|
||||||
|
|
||||||
context = this.context;
|
context = this.context;
|
||||||
${records}
|
${records}
|
||||||
|
@ -153,10 +154,10 @@ ${records}
|
||||||
|
|
||||||
function notifyTemplate(index:number):string{
|
function notifyTemplate(index:number):string{
|
||||||
return `
|
return `
|
||||||
if (${CHANGES_LOCAL}.length > 0) {
|
if (${CHANGES_LOCAL} && ${CHANGES_LOCAL}.length > 0) {
|
||||||
if(throwOnChange) ${UTIL}.throwOnChange(${PROTOS_ACCESSOR}[${index}], ${CHANGES_LOCAL}[0]);
|
if(throwOnChange) ${UTIL}.throwOnChange(${PROTOS_ACCESSOR}[${index}], ${CHANGES_LOCAL}[0]);
|
||||||
${DISPATCHER_ACCESSOR}.onRecordChange(${PROTOS_ACCESSOR}[${index}].groupMemento, ${CHANGES_LOCAL});
|
${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 `
|
return `
|
||||||
${CHANGE_LOCAL} = ${UTIL}.structuralCheck(${field}, ${context});
|
${CHANGE_LOCAL} = ${UTIL}.structuralCheck(${field}, ${context});
|
||||||
if (${CHANGE_LOCAL}) {
|
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;
|
${field} = ${CHANGE_LOCAL}.currentValue;
|
||||||
}
|
}
|
||||||
${notify}
|
${notify}
|
||||||
|
@ -222,7 +224,8 @@ if (${cond}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function addSimpleChangeRecordTemplate(protoIndex:number, oldValue:string, newValue:string) {
|
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}));`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
export class ChangeDetectionUtil {
|
||||||
static unitialized() {
|
static unitialized() {
|
||||||
return uninitialized;
|
return uninitialized;
|
||||||
|
@ -128,11 +194,29 @@ export class ChangeDetectionUtil {
|
||||||
throw new ExpressionChangedAfterItHasBeenChecked(proto, change);
|
throw new ExpressionChangedAfterItHasBeenChecked(proto, change);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static simpleChange(previousValue:any, currentValue:any):SimpleChange {
|
||||||
|
return _simpleChange(previousValue, currentValue);
|
||||||
|
}
|
||||||
|
|
||||||
static changeRecord(memento:any, change:any):ChangeRecord {
|
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 {
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -62,7 +62,8 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
|
||||||
|
|
||||||
if (isPresent(change)) {
|
if (isPresent(change)) {
|
||||||
currentGroup = proto.groupMemento;
|
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)) {
|
if (proto.lastInGroup && isPresent(updatedRecords)) {
|
||||||
|
@ -100,7 +101,7 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
|
||||||
this._setChanged(proto, true);
|
this._setChanged(proto, true);
|
||||||
|
|
||||||
if (proto.lastInBinding) {
|
if (proto.lastInBinding) {
|
||||||
return new SimpleChange(prevValue, currValue);
|
return ChangeDetectionUtil.simpleChange(prevValue, currValue);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -164,22 +165,6 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
|
||||||
return change;
|
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) {
|
_readContext(proto:ProtoRecord) {
|
||||||
return this.values[proto.contextIndex];
|
return this.values[proto.contextIndex];
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,10 @@ export function main() {
|
||||||
expect(dispatcher.log).toEqual(['name=misko']);
|
expect(dispatcher.log).toEqual(['name=misko']);
|
||||||
dispatcher.clear();
|
dispatcher.clear();
|
||||||
|
|
||||||
|
cd.detectChanges();
|
||||||
|
expect(dispatcher.log).toEqual([]);
|
||||||
|
dispatcher.clear();
|
||||||
|
|
||||||
person.name = "Misko";
|
person.name = "Misko";
|
||||||
cd.detectChanges();
|
cd.detectChanges();
|
||||||
expect(dispatcher.log).toEqual(['name=Misko']);
|
expect(dispatcher.log).toEqual(['name=Misko']);
|
||||||
|
|
Loading…
Reference in New Issue