refactor(view): change view to pass all bindings to proto change detector at once
This commit is contained in:
parent
1adb23d222
commit
3273adade5
|
@ -7,7 +7,7 @@ export {ExpressionChangedAfterItHasBeenChecked, ChangeDetectionError}
|
|||
from './src/change_detection/exceptions';
|
||||
export {ChangeRecord, ChangeDispatcher, ChangeDetector,
|
||||
CHECK_ONCE, CHECK_ALWAYS, DETACHED, CHECKED} from './src/change_detection/interfaces';
|
||||
export {ProtoChangeDetector, DynamicProtoChangeDetector, JitProtoChangeDetector}
|
||||
export {ProtoChangeDetector, DynamicProtoChangeDetector, JitProtoChangeDetector, BindingRecord}
|
||||
from './src/change_detection/proto_change_detector';
|
||||
export {DynamicChangeDetector}
|
||||
from './src/change_detection/dynamic_change_detector';
|
||||
|
|
|
@ -45,36 +45,44 @@ import {
|
|||
|
||||
export class ProtoChangeDetector {
|
||||
addAst(ast:AST, bindingMemento:any, directiveMemento:any = null){}
|
||||
instantiate(dispatcher:any):ChangeDetector{
|
||||
instantiate(dispatcher:any, bindingRecords:List):ChangeDetector{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export class BindingRecord {
|
||||
ast:AST;
|
||||
bindingMemento:any;
|
||||
directiveMemento:any;
|
||||
|
||||
constructor(ast:AST, bindingMemento:any, directiveMemento:any) {
|
||||
this.ast = ast;
|
||||
this.bindingMemento = bindingMemento;
|
||||
this.directiveMemento = directiveMemento;
|
||||
}
|
||||
}
|
||||
|
||||
export class DynamicProtoChangeDetector extends ProtoChangeDetector {
|
||||
_records:List<ProtoRecord>;
|
||||
_recordBuilder:ProtoRecordBuilder;
|
||||
_pipeRegistry:PipeRegistry;
|
||||
_records:List<ProtoRecord>;
|
||||
|
||||
constructor(pipeRegistry:PipeRegistry) {
|
||||
super();
|
||||
this._pipeRegistry = pipeRegistry;
|
||||
this._records = null;
|
||||
this._recordBuilder = new ProtoRecordBuilder();
|
||||
}
|
||||
|
||||
addAst(ast:AST, bindingMemento:any, directiveMemento:any = null) {
|
||||
this._recordBuilder.addAst(ast, bindingMemento, directiveMemento);
|
||||
}
|
||||
|
||||
instantiate(dispatcher:any) {
|
||||
this._createRecordsIfNecessary();
|
||||
instantiate(dispatcher:any, bindingRecords:List) {
|
||||
this._createRecordsIfNecessary(bindingRecords);
|
||||
return new DynamicChangeDetector(dispatcher, this._pipeRegistry, this._records);
|
||||
}
|
||||
|
||||
_createRecordsIfNecessary() {
|
||||
_createRecordsIfNecessary(bindingRecords:List) {
|
||||
if (isBlank(this._records)) {
|
||||
var records = this._recordBuilder.records;
|
||||
this._records = coalesce(records);
|
||||
var recordBuilder = new ProtoRecordBuilder();
|
||||
ListWrapper.forEach(bindingRecords, (r) => {
|
||||
recordBuilder.addAst(r.ast, r.bindingMemento, r.directiveMemento);
|
||||
});
|
||||
this._records = coalesce(recordBuilder.records);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -82,29 +90,27 @@ export class DynamicProtoChangeDetector extends ProtoChangeDetector {
|
|||
var _jitProtoChangeDetectorClassCounter:number = 0;
|
||||
export class JitProtoChangeDetector extends ProtoChangeDetector {
|
||||
_factory:Function;
|
||||
_recordBuilder:ProtoRecordBuilder;
|
||||
_pipeRegistry;
|
||||
|
||||
constructor(pipeRegistry) {
|
||||
super();
|
||||
this._pipeRegistry = pipeRegistry;
|
||||
this._factory = null;
|
||||
this._recordBuilder = new ProtoRecordBuilder();
|
||||
}
|
||||
|
||||
addAst(ast:AST, bindingMemento:any, directiveMemento:any = null) {
|
||||
this._recordBuilder.addAst(ast, bindingMemento, directiveMemento);
|
||||
}
|
||||
|
||||
instantiate(dispatcher:any) {
|
||||
this._createFactoryIfNecessary();
|
||||
instantiate(dispatcher:any, bindingRecords:List) {
|
||||
this._createFactoryIfNecessary(bindingRecords);
|
||||
return this._factory(dispatcher, this._pipeRegistry);
|
||||
}
|
||||
|
||||
_createFactoryIfNecessary() {
|
||||
_createFactoryIfNecessary(bindingRecords:List) {
|
||||
if (isBlank(this._factory)) {
|
||||
var recordBuilder = new ProtoRecordBuilder();
|
||||
ListWrapper.forEach(bindingRecords, (r) => {
|
||||
recordBuilder.addAst(r.ast, r.bindingMemento, r.directiveMemento);
|
||||
});
|
||||
var c = _jitProtoChangeDetectorClassCounter++;
|
||||
var records = coalesce(this._recordBuilder.records);
|
||||
var records = coalesce(recordBuilder.records);
|
||||
var typeName = `ChangeDetector${c}`;
|
||||
this._factory = new ChangeDetectorJITGenerator(typeName, records).generate();
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {Promise} from 'angular2/src/facade/async';
|
||||
import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src/facade/collection';
|
||||
import {AST, ContextWithVariableBindings, ChangeDispatcher, ProtoChangeDetector, ChangeDetector, ChangeRecord}
|
||||
from 'angular2/change_detection';
|
||||
import {AST, ContextWithVariableBindings, ChangeDispatcher, ProtoChangeDetector, ChangeDetector,
|
||||
ChangeRecord, BindingRecord} from 'angular2/change_detection';
|
||||
|
||||
import {ProtoElementInjector, ElementInjector, PreBuiltObjects} from './element_injector';
|
||||
import {BindingPropagationConfig} from './binding_propagation_config';
|
||||
|
@ -46,10 +46,10 @@ export class View {
|
|||
context: any;
|
||||
contextWithLocals:ContextWithVariableBindings;
|
||||
|
||||
constructor(proto:ProtoView, nodes:List, protoChangeDetector:ProtoChangeDetector, protoContextLocals:Map) {
|
||||
constructor(proto:ProtoView, nodes:List, protoContextLocals:Map) {
|
||||
this.proto = proto;
|
||||
this.nodes = nodes;
|
||||
this.changeDetector = protoChangeDetector.instantiate(this);
|
||||
this.changeDetector = null;
|
||||
this.elementInjectors = null;
|
||||
this.rootElementInjectors = null;
|
||||
this.textNodes = null;
|
||||
|
@ -63,8 +63,9 @@ export class View {
|
|||
: null;
|
||||
}
|
||||
|
||||
init(elementInjectors:List, rootElementInjectors:List, textNodes: List, bindElements:List,
|
||||
init(changeDetector:ChangeDetector, elementInjectors:List, rootElementInjectors:List, textNodes: List, bindElements:List,
|
||||
viewContainers:List, preBuiltObjects:List, componentChildViews:List) {
|
||||
this.changeDetector = changeDetector;
|
||||
this.elementInjectors = elementInjectors;
|
||||
this.rootElementInjectors = rootElementInjectors;
|
||||
this.textNodes = textNodes;
|
||||
|
@ -294,12 +295,13 @@ export class ProtoView {
|
|||
_viewPool: ViewPool;
|
||||
stylePromises: List<Promise>;
|
||||
// List<Map<eventName, handler>>, indexed by binder index
|
||||
eventHandlers: List;
|
||||
eventHandlers:List;
|
||||
bindingRecords:List;
|
||||
|
||||
constructor(
|
||||
template,
|
||||
protoChangeDetector:ProtoChangeDetector,
|
||||
shadowDomStrategy: ShadowDomStrategy) {
|
||||
shadowDomStrategy:ShadowDomStrategy) {
|
||||
this.element = template;
|
||||
this.elementBinders = [];
|
||||
this.variableBindings = MapWrapper.create();
|
||||
|
@ -315,6 +317,7 @@ export class ProtoView {
|
|||
this._viewPool = new ViewPool(VIEW_POOL_CAPACITY);
|
||||
this.stylePromises = [];
|
||||
this.eventHandlers = [];
|
||||
this.bindingRecords = [];
|
||||
}
|
||||
|
||||
// TODO(rado): hostElementInjector should be moved to hydrate phase.
|
||||
|
@ -357,7 +360,9 @@ export class ProtoView {
|
|||
viewNodes = [rootElementClone];
|
||||
}
|
||||
|
||||
var view = new View(this, viewNodes, this.protoChangeDetector, this.protoContextLocals);
|
||||
var view = new View(this, viewNodes, this.protoContextLocals);
|
||||
var changeDetector = this.protoChangeDetector.instantiate(view, this.bindingRecords);
|
||||
|
||||
var binders = this.elementBinders;
|
||||
var elementInjectors = ListWrapper.createFixedSize(binders.length);
|
||||
var eventHandlers = ListWrapper.createFixedSize(binders.length);
|
||||
|
@ -413,12 +418,12 @@ export class ProtoView {
|
|||
if (isPresent(binder.componentDirective)) {
|
||||
var strategy = this.shadowDomStrategy;
|
||||
var childView = binder.nestedProtoView.instantiate(elementInjector, eventManager);
|
||||
view.changeDetector.addChild(childView.changeDetector);
|
||||
changeDetector.addChild(childView.changeDetector);
|
||||
|
||||
lightDom = strategy.constructLightDom(view, childView, element);
|
||||
strategy.attachTemplate(element, childView);
|
||||
|
||||
bindingPropagationConfig = new BindingPropagationConfig(view.changeDetector);
|
||||
bindingPropagationConfig = new BindingPropagationConfig(changeDetector);
|
||||
|
||||
ListWrapper.push(componentChildViews, childView);
|
||||
}
|
||||
|
@ -454,7 +459,7 @@ export class ProtoView {
|
|||
|
||||
this.eventHandlers = eventHandlers;
|
||||
|
||||
view.init(elementInjectors, rootElementInjectors, textNodes, elementsWithPropertyBindings,
|
||||
view.init(changeDetector, elementInjectors, rootElementInjectors, textNodes, elementsWithPropertyBindings,
|
||||
viewContainers, preBuiltObjects, componentChildViews);
|
||||
|
||||
return view;
|
||||
|
@ -519,7 +524,7 @@ export class ProtoView {
|
|||
}
|
||||
ListWrapper.push(elBinder.textNodeIndices, indexInParent);
|
||||
var memento = this.textNodesWithBindingCount++;
|
||||
this.protoChangeDetector.addAst(expression, memento);
|
||||
ListWrapper.push(this.bindingRecords, new BindingRecord(expression, memento, null));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -532,7 +537,7 @@ export class ProtoView {
|
|||
this.elementsWithBindingCount++;
|
||||
}
|
||||
var memento = new ElementBindingMemento(this.elementsWithBindingCount-1, setterName, setter);
|
||||
this.protoChangeDetector.addAst(expression, memento);
|
||||
ListWrapper.push(this.bindingRecords, new BindingRecord(expression, memento, null));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -579,7 +584,7 @@ export class ProtoView {
|
|||
setter
|
||||
);
|
||||
var directiveMemento = DirectiveMemento.get(bindingMemento);
|
||||
this.protoChangeDetector.addAst(expression, bindingMemento, directiveMemento);
|
||||
ListWrapper.push(this.bindingRecords, new BindingRecord(expression, bindingMemento, directiveMemento));
|
||||
}
|
||||
|
||||
// Create a rootView as if the compiler encountered <rootcmp></rootcmp>,
|
||||
|
|
|
@ -6,7 +6,7 @@ import {List, ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/faca
|
|||
import {Parser} from 'angular2/src/change_detection/parser/parser';
|
||||
import {Lexer} from 'angular2/src/change_detection/parser/lexer';
|
||||
|
||||
import {ChangeDispatcher, DynamicChangeDetector, ChangeDetectionError, ContextWithVariableBindings,
|
||||
import {ChangeDispatcher, DynamicChangeDetector, ChangeDetectionError, ContextWithVariableBindings, BindingRecord,
|
||||
PipeRegistry, Pipe, NO_CHANGE, CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED} from 'angular2/change_detection';
|
||||
|
||||
import {ChangeDetectionUtil} from 'angular2/src/change_detection/change_detection_util';
|
||||
|
@ -30,9 +30,8 @@ export function main() {
|
|||
|
||||
function createChangeDetector(memo:string, exp:string, context = null, registry = null) {
|
||||
var pcd = createProtoChangeDetector(registry);
|
||||
pcd.addAst(ast(exp), memo, memo);
|
||||
var dispatcher = new TestDispatcher();
|
||||
var cd = pcd.instantiate(dispatcher);
|
||||
var cd = pcd.instantiate(dispatcher, [new BindingRecord(ast(exp), memo, memo)]);
|
||||
cd.hydrate(context);
|
||||
|
||||
return {"changeDetector" : cd, "dispatcher" : dispatcher};
|
||||
|
@ -179,10 +178,9 @@ export function main() {
|
|||
var parser = new Parser(new Lexer());
|
||||
var pcd = createProtoChangeDetector();
|
||||
var ast = parser.parseInterpolation("B{{a}}A", "location");
|
||||
pcd.addAst(ast, "memo", "memo");
|
||||
|
||||
var dispatcher = new TestDispatcher();
|
||||
var cd = pcd.instantiate(dispatcher);
|
||||
var cd = pcd.instantiate(dispatcher, [new BindingRecord(ast, "memo", "memo")]);
|
||||
cd.hydrate(new TestData("value"));
|
||||
|
||||
cd.detectChanges();
|
||||
|
@ -230,12 +228,13 @@ export function main() {
|
|||
describe("group changes", () => {
|
||||
it("should notify the dispatcher when a group of records changes", () => {
|
||||
var pcd = createProtoChangeDetector();
|
||||
pcd.addAst(ast("1 + 2"), "memo", "1");
|
||||
pcd.addAst(ast("10 + 20"), "memo", "1");
|
||||
pcd.addAst(ast("100 + 200"), "memo2", "2");
|
||||
|
||||
var dispatcher = new TestDispatcher();
|
||||
var cd = pcd.instantiate(dispatcher);
|
||||
var cd = pcd.instantiate(dispatcher, [
|
||||
new BindingRecord(ast("1 + 2"), "memo", "1"),
|
||||
new BindingRecord(ast("10 + 20"), "memo", "1"),
|
||||
new BindingRecord(ast("100 + 200"), "memo", "2")
|
||||
]);
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
|
@ -244,12 +243,12 @@ export function main() {
|
|||
|
||||
it("should notify the dispatcher before switching to the next group", () => {
|
||||
var pcd = createProtoChangeDetector();
|
||||
pcd.addAst(ast("a()"), "a", "1");
|
||||
pcd.addAst(ast("b()"), "b", "2");
|
||||
pcd.addAst(ast("c()"), "c", "2");
|
||||
|
||||
var dispatcher = new TestDispatcher();
|
||||
var cd = pcd.instantiate(dispatcher);
|
||||
var cd = pcd.instantiate(dispatcher, [
|
||||
new BindingRecord(ast("a()"), "a", "1"),
|
||||
new BindingRecord(ast("b()"), "b", "2"),
|
||||
new BindingRecord(ast("c()"), "c", "2")
|
||||
]);
|
||||
|
||||
var tr = new TestRecord();
|
||||
tr.a = () => {
|
||||
|
@ -279,7 +278,9 @@ export function main() {
|
|||
pcd.addAst(ast("a"), "a", 1);
|
||||
|
||||
var dispatcher = new TestDispatcher();
|
||||
var cd = pcd.instantiate(dispatcher);
|
||||
var cd = pcd.instantiate(dispatcher, [
|
||||
new BindingRecord(ast("a"), "a", 1)
|
||||
]);
|
||||
cd.hydrate(new TestData('value'));
|
||||
|
||||
expect(() => {
|
||||
|
@ -292,9 +293,9 @@ export function main() {
|
|||
describe("error handling", () => {
|
||||
xit("should wrap exceptions into ChangeDetectionError", () => {
|
||||
var pcd = createProtoChangeDetector();
|
||||
pcd.addAst(ast('invalidProp', 'someComponent'), "a", 1);
|
||||
|
||||
var cd = pcd.instantiate(new TestDispatcher());
|
||||
var cd = pcd.instantiate(new TestDispatcher(), [
|
||||
new BindingRecord(ast("invalidProp", "someComponent"), "a", 1)
|
||||
]);
|
||||
cd.hydrate(null);
|
||||
|
||||
try {
|
||||
|
@ -349,10 +350,10 @@ export function main() {
|
|||
|
||||
beforeEach(() => {
|
||||
var protoParent = createProtoChangeDetector();
|
||||
parent = protoParent.instantiate(null);
|
||||
parent = protoParent.instantiate(null, []);
|
||||
|
||||
var protoChild = createProtoChangeDetector();
|
||||
child = protoChild.instantiate(null);
|
||||
child = protoChild.instantiate(null, []);
|
||||
});
|
||||
|
||||
it("should add children", () => {
|
||||
|
@ -395,7 +396,7 @@ export function main() {
|
|||
});
|
||||
|
||||
it("should change CHECK_ONCE to CHECKED", () => {
|
||||
var cd = createProtoChangeDetector().instantiate(null);
|
||||
var cd = createProtoChangeDetector().instantiate(null, []);
|
||||
cd.mode = CHECK_ONCE;
|
||||
|
||||
cd.detectChanges();
|
||||
|
@ -404,7 +405,7 @@ export function main() {
|
|||
});
|
||||
|
||||
it("should not change the CHECK_ALWAYS", () => {
|
||||
var cd = createProtoChangeDetector().instantiate(null);
|
||||
var cd = createProtoChangeDetector().instantiate(null, []);
|
||||
cd.mode = CHECK_ALWAYS;
|
||||
|
||||
cd.detectChanges();
|
||||
|
@ -415,7 +416,7 @@ export function main() {
|
|||
|
||||
describe("markPathToRootAsCheckOnce", () => {
|
||||
function changeDetector(mode, parent) {
|
||||
var cd = createProtoChangeDetector().instantiate(null);
|
||||
var cd = createProtoChangeDetector().instantiate(null, []);
|
||||
cd.mode = mode;
|
||||
if (isPresent(parent)) parent.addChild(cd);
|
||||
return cd;
|
||||
|
|
|
@ -12,7 +12,6 @@ import {NgElement} from 'angular2/src/core/dom/element';
|
|||
import {LightDom, DestinationLightDom} from 'angular2/src/core/compiler/shadow_dom_emulation/light_dom';
|
||||
import {Directive} from 'angular2/src/core/annotations/annotations';
|
||||
import {BindingPropagationConfig} from 'angular2/src/core/compiler/binding_propagation_config';
|
||||
import {DynamicProtoChangeDetector} from 'angular2/change_detection';
|
||||
|
||||
@proxy
|
||||
@IMPLEMENTS(View)
|
||||
|
@ -476,7 +475,7 @@ export function main() {
|
|||
StringMapWrapper.set(handlers, 'click', (e, view) => { called = true;});
|
||||
var pv = new ProtoView(null, null, null);
|
||||
pv.eventHandlers = [handlers];
|
||||
var view = new View(pv, null, new DynamicProtoChangeDetector(null), MapWrapper.create());
|
||||
var view = new View(pv, null, MapWrapper.create());
|
||||
var preBuildObject = new PreBuiltObjects(view, null, null, null, null);
|
||||
var inj = injector([NeedsEventEmitter], null, null, preBuildObject);
|
||||
inj.get(NeedsEventEmitter).click();
|
||||
|
|
|
@ -10,8 +10,9 @@ import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_str
|
|||
import {DynamicProtoChangeDetector, ChangeDetector, Lexer, Parser} from 'angular2/change_detection';
|
||||
|
||||
function createView(nodes) {
|
||||
var view = new View(null, nodes, new DynamicProtoChangeDetector(null), MapWrapper.create());
|
||||
view.init([], [], [], [], [], [], []);
|
||||
var view = new View(null, nodes, MapWrapper.create());
|
||||
var cd = new DynamicProtoChangeDetector(null).instantiate(view, []);
|
||||
view.init(cd, [], [], [], [], [], [], []);
|
||||
return view;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,8 @@ import {
|
|||
ChangeDispatcher,
|
||||
ChangeDetection,
|
||||
dynamicChangeDetection,
|
||||
jitChangeDetection
|
||||
jitChangeDetection,
|
||||
BindingRecord
|
||||
} from 'angular2/change_detection';
|
||||
|
||||
|
||||
|
@ -104,31 +105,28 @@ function setUpChangeDetection(changeDetection:ChangeDetection, iterations) {
|
|||
var parser = new Parser(new Lexer());
|
||||
|
||||
var parentProto = changeDetection.createProtoChangeDetector('parent');
|
||||
var parentCd = parentProto.instantiate(dispatcher);
|
||||
var parentCd = parentProto.instantiate(dispatcher, []);
|
||||
|
||||
var proto = changeDetection.createProtoChangeDetector("proto");
|
||||
var astWithSource = [
|
||||
parser.parseBinding('field0', null),
|
||||
parser.parseBinding('field1', null),
|
||||
parser.parseBinding('field2', null),
|
||||
parser.parseBinding('field3', null),
|
||||
parser.parseBinding('field4', null),
|
||||
parser.parseBinding('field5', null),
|
||||
parser.parseBinding('field6', null),
|
||||
parser.parseBinding('field7', null),
|
||||
parser.parseBinding('field8', null),
|
||||
parser.parseBinding('field9', null)
|
||||
var bindingRecords = [
|
||||
new BindingRecord(parser.parseBinding('field0', null), "memo", 0),
|
||||
new BindingRecord(parser.parseBinding('field1', null), "memo", 1),
|
||||
new BindingRecord(parser.parseBinding('field2', null), "memo", 2),
|
||||
new BindingRecord(parser.parseBinding('field3', null), "memo", 3),
|
||||
new BindingRecord(parser.parseBinding('field4', null), "memo", 4),
|
||||
new BindingRecord(parser.parseBinding('field5', null), "memo", 5),
|
||||
new BindingRecord(parser.parseBinding('field6', null), "memo", 6),
|
||||
new BindingRecord(parser.parseBinding('field7', null), "memo", 7),
|
||||
new BindingRecord(parser.parseBinding('field8', null), "memo", 8),
|
||||
new BindingRecord(parser.parseBinding('field9', null), "memo", 9)
|
||||
];
|
||||
for (var j = 0; j < 10; ++j) {
|
||||
proto.addAst(astWithSource[j].ast, "memo", j);
|
||||
}
|
||||
|
||||
for (var i = 0; i < iterations; ++i) {
|
||||
var obj = new Obj();
|
||||
for (var j = 0; j < 10; ++j) {
|
||||
obj.setField(j, i);
|
||||
}
|
||||
var cd = proto.instantiate(dispatcher);
|
||||
var cd = proto.instantiate(dispatcher, bindingRecords);
|
||||
cd.hydrate(obj);
|
||||
parentCd.addChild(cd);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue