Skip to content

Commit 3273ada

Browse files
committed
refactor(view): change view to pass all bindings to proto change detector at once
1 parent 1adb23d commit 3273ada

7 files changed

Lines changed: 93 additions & 83 deletions

File tree

modules/angular2/change_detection.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export {ExpressionChangedAfterItHasBeenChecked, ChangeDetectionError}
77
from './src/change_detection/exceptions';
88
export {ChangeRecord, ChangeDispatcher, ChangeDetector,
99
CHECK_ONCE, CHECK_ALWAYS, DETACHED, CHECKED} from './src/change_detection/interfaces';
10-
export {ProtoChangeDetector, DynamicProtoChangeDetector, JitProtoChangeDetector}
10+
export {ProtoChangeDetector, DynamicProtoChangeDetector, JitProtoChangeDetector, BindingRecord}
1111
from './src/change_detection/proto_change_detector';
1212
export {DynamicChangeDetector}
1313
from './src/change_detection/dynamic_change_detector';

modules/angular2/src/change_detection/proto_change_detector.js

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -45,66 +45,72 @@ import {
4545

4646
export class ProtoChangeDetector {
4747
addAst(ast:AST, bindingMemento:any, directiveMemento:any = null){}
48-
instantiate(dispatcher:any):ChangeDetector{
48+
instantiate(dispatcher:any, bindingRecords:List):ChangeDetector{
4949
return null;
5050
}
5151
}
5252

53+
export class BindingRecord {
54+
ast:AST;
55+
bindingMemento:any;
56+
directiveMemento:any;
57+
58+
constructor(ast:AST, bindingMemento:any, directiveMemento:any) {
59+
this.ast = ast;
60+
this.bindingMemento = bindingMemento;
61+
this.directiveMemento = directiveMemento;
62+
}
63+
}
64+
5365
export class DynamicProtoChangeDetector extends ProtoChangeDetector {
54-
_records:List<ProtoRecord>;
55-
_recordBuilder:ProtoRecordBuilder;
5666
_pipeRegistry:PipeRegistry;
67+
_records:List<ProtoRecord>;
5768

5869
constructor(pipeRegistry:PipeRegistry) {
5970
super();
6071
this._pipeRegistry = pipeRegistry;
61-
this._records = null;
62-
this._recordBuilder = new ProtoRecordBuilder();
63-
}
64-
65-
addAst(ast:AST, bindingMemento:any, directiveMemento:any = null) {
66-
this._recordBuilder.addAst(ast, bindingMemento, directiveMemento);
6772
}
6873

69-
instantiate(dispatcher:any) {
70-
this._createRecordsIfNecessary();
74+
instantiate(dispatcher:any, bindingRecords:List) {
75+
this._createRecordsIfNecessary(bindingRecords);
7176
return new DynamicChangeDetector(dispatcher, this._pipeRegistry, this._records);
7277
}
7378

74-
_createRecordsIfNecessary() {
79+
_createRecordsIfNecessary(bindingRecords:List) {
7580
if (isBlank(this._records)) {
76-
var records = this._recordBuilder.records;
77-
this._records = coalesce(records);
81+
var recordBuilder = new ProtoRecordBuilder();
82+
ListWrapper.forEach(bindingRecords, (r) => {
83+
recordBuilder.addAst(r.ast, r.bindingMemento, r.directiveMemento);
84+
});
85+
this._records = coalesce(recordBuilder.records);
7886
}
7987
}
8088
}
8189

8290
var _jitProtoChangeDetectorClassCounter:number = 0;
8391
export class JitProtoChangeDetector extends ProtoChangeDetector {
8492
_factory:Function;
85-
_recordBuilder:ProtoRecordBuilder;
8693
_pipeRegistry;
8794

8895
constructor(pipeRegistry) {
8996
super();
9097
this._pipeRegistry = pipeRegistry;
9198
this._factory = null;
92-
this._recordBuilder = new ProtoRecordBuilder();
93-
}
94-
95-
addAst(ast:AST, bindingMemento:any, directiveMemento:any = null) {
96-
this._recordBuilder.addAst(ast, bindingMemento, directiveMemento);
9799
}
98100

99-
instantiate(dispatcher:any) {
100-
this._createFactoryIfNecessary();
101+
instantiate(dispatcher:any, bindingRecords:List) {
102+
this._createFactoryIfNecessary(bindingRecords);
101103
return this._factory(dispatcher, this._pipeRegistry);
102104
}
103105

104-
_createFactoryIfNecessary() {
106+
_createFactoryIfNecessary(bindingRecords:List) {
105107
if (isBlank(this._factory)) {
108+
var recordBuilder = new ProtoRecordBuilder();
109+
ListWrapper.forEach(bindingRecords, (r) => {
110+
recordBuilder.addAst(r.ast, r.bindingMemento, r.directiveMemento);
111+
});
106112
var c = _jitProtoChangeDetectorClassCounter++;
107-
var records = coalesce(this._recordBuilder.records);
113+
var records = coalesce(recordBuilder.records);
108114
var typeName = `ChangeDetector${c}`;
109115
this._factory = new ChangeDetectorJITGenerator(typeName, records).generate();
110116
}

modules/angular2/src/core/compiler/view.js

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import {DOM} from 'angular2/src/dom/dom_adapter';
22
import {Promise} from 'angular2/src/facade/async';
33
import {ListWrapper, MapWrapper, Map, StringMapWrapper, List} from 'angular2/src/facade/collection';
4-
import {AST, ContextWithVariableBindings, ChangeDispatcher, ProtoChangeDetector, ChangeDetector, ChangeRecord}
5-
from 'angular2/change_detection';
4+
import {AST, ContextWithVariableBindings, ChangeDispatcher, ProtoChangeDetector, ChangeDetector,
5+
ChangeRecord, BindingRecord} from 'angular2/change_detection';
66

77
import {ProtoElementInjector, ElementInjector, PreBuiltObjects} from './element_injector';
88
import {BindingPropagationConfig} from './binding_propagation_config';
@@ -46,10 +46,10 @@ export class View {
4646
context: any;
4747
contextWithLocals:ContextWithVariableBindings;
4848

49-
constructor(proto:ProtoView, nodes:List, protoChangeDetector:ProtoChangeDetector, protoContextLocals:Map) {
49+
constructor(proto:ProtoView, nodes:List, protoContextLocals:Map) {
5050
this.proto = proto;
5151
this.nodes = nodes;
52-
this.changeDetector = protoChangeDetector.instantiate(this);
52+
this.changeDetector = null;
5353
this.elementInjectors = null;
5454
this.rootElementInjectors = null;
5555
this.textNodes = null;
@@ -63,8 +63,9 @@ export class View {
6363
: null;
6464
}
6565

66-
init(elementInjectors:List, rootElementInjectors:List, textNodes: List, bindElements:List,
66+
init(changeDetector:ChangeDetector, elementInjectors:List, rootElementInjectors:List, textNodes: List, bindElements:List,
6767
viewContainers:List, preBuiltObjects:List, componentChildViews:List) {
68+
this.changeDetector = changeDetector;
6869
this.elementInjectors = elementInjectors;
6970
this.rootElementInjectors = rootElementInjectors;
7071
this.textNodes = textNodes;
@@ -294,12 +295,13 @@ export class ProtoView {
294295
_viewPool: ViewPool;
295296
stylePromises: List<Promise>;
296297
// List<Map<eventName, handler>>, indexed by binder index
297-
eventHandlers: List;
298+
eventHandlers:List;
299+
bindingRecords:List;
298300

299301
constructor(
300302
template,
301303
protoChangeDetector:ProtoChangeDetector,
302-
shadowDomStrategy: ShadowDomStrategy) {
304+
shadowDomStrategy:ShadowDomStrategy) {
303305
this.element = template;
304306
this.elementBinders = [];
305307
this.variableBindings = MapWrapper.create();
@@ -315,6 +317,7 @@ export class ProtoView {
315317
this._viewPool = new ViewPool(VIEW_POOL_CAPACITY);
316318
this.stylePromises = [];
317319
this.eventHandlers = [];
320+
this.bindingRecords = [];
318321
}
319322

320323
// TODO(rado): hostElementInjector should be moved to hydrate phase.
@@ -357,7 +360,9 @@ export class ProtoView {
357360
viewNodes = [rootElementClone];
358361
}
359362

360-
var view = new View(this, viewNodes, this.protoChangeDetector, this.protoContextLocals);
363+
var view = new View(this, viewNodes, this.protoContextLocals);
364+
var changeDetector = this.protoChangeDetector.instantiate(view, this.bindingRecords);
365+
361366
var binders = this.elementBinders;
362367
var elementInjectors = ListWrapper.createFixedSize(binders.length);
363368
var eventHandlers = ListWrapper.createFixedSize(binders.length);
@@ -413,12 +418,12 @@ export class ProtoView {
413418
if (isPresent(binder.componentDirective)) {
414419
var strategy = this.shadowDomStrategy;
415420
var childView = binder.nestedProtoView.instantiate(elementInjector, eventManager);
416-
view.changeDetector.addChild(childView.changeDetector);
421+
changeDetector.addChild(childView.changeDetector);
417422

418423
lightDom = strategy.constructLightDom(view, childView, element);
419424
strategy.attachTemplate(element, childView);
420425

421-
bindingPropagationConfig = new BindingPropagationConfig(view.changeDetector);
426+
bindingPropagationConfig = new BindingPropagationConfig(changeDetector);
422427

423428
ListWrapper.push(componentChildViews, childView);
424429
}
@@ -454,7 +459,7 @@ export class ProtoView {
454459

455460
this.eventHandlers = eventHandlers;
456461

457-
view.init(elementInjectors, rootElementInjectors, textNodes, elementsWithPropertyBindings,
462+
view.init(changeDetector, elementInjectors, rootElementInjectors, textNodes, elementsWithPropertyBindings,
458463
viewContainers, preBuiltObjects, componentChildViews);
459464

460465
return view;
@@ -519,7 +524,7 @@ export class ProtoView {
519524
}
520525
ListWrapper.push(elBinder.textNodeIndices, indexInParent);
521526
var memento = this.textNodesWithBindingCount++;
522-
this.protoChangeDetector.addAst(expression, memento);
527+
ListWrapper.push(this.bindingRecords, new BindingRecord(expression, memento, null));
523528
}
524529

525530
/**
@@ -532,7 +537,7 @@ export class ProtoView {
532537
this.elementsWithBindingCount++;
533538
}
534539
var memento = new ElementBindingMemento(this.elementsWithBindingCount-1, setterName, setter);
535-
this.protoChangeDetector.addAst(expression, memento);
540+
ListWrapper.push(this.bindingRecords, new BindingRecord(expression, memento, null));
536541
}
537542

538543
/**
@@ -579,7 +584,7 @@ export class ProtoView {
579584
setter
580585
);
581586
var directiveMemento = DirectiveMemento.get(bindingMemento);
582-
this.protoChangeDetector.addAst(expression, bindingMemento, directiveMemento);
587+
ListWrapper.push(this.bindingRecords, new BindingRecord(expression, bindingMemento, directiveMemento));
583588
}
584589

585590
// Create a rootView as if the compiler encountered <rootcmp></rootcmp>,

modules/angular2/test/change_detection/change_detection_spec.js

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {List, ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/faca
66
import {Parser} from 'angular2/src/change_detection/parser/parser';
77
import {Lexer} from 'angular2/src/change_detection/parser/lexer';
88

9-
import {ChangeDispatcher, DynamicChangeDetector, ChangeDetectionError, ContextWithVariableBindings,
9+
import {ChangeDispatcher, DynamicChangeDetector, ChangeDetectionError, ContextWithVariableBindings, BindingRecord,
1010
PipeRegistry, Pipe, NO_CHANGE, CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED} from 'angular2/change_detection';
1111

1212
import {ChangeDetectionUtil} from 'angular2/src/change_detection/change_detection_util';
@@ -30,9 +30,8 @@ export function main() {
3030

3131
function createChangeDetector(memo:string, exp:string, context = null, registry = null) {
3232
var pcd = createProtoChangeDetector(registry);
33-
pcd.addAst(ast(exp), memo, memo);
3433
var dispatcher = new TestDispatcher();
35-
var cd = pcd.instantiate(dispatcher);
34+
var cd = pcd.instantiate(dispatcher, [new BindingRecord(ast(exp), memo, memo)]);
3635
cd.hydrate(context);
3736

3837
return {"changeDetector" : cd, "dispatcher" : dispatcher};
@@ -179,10 +178,9 @@ export function main() {
179178
var parser = new Parser(new Lexer());
180179
var pcd = createProtoChangeDetector();
181180
var ast = parser.parseInterpolation("B{{a}}A", "location");
182-
pcd.addAst(ast, "memo", "memo");
183181

184182
var dispatcher = new TestDispatcher();
185-
var cd = pcd.instantiate(dispatcher);
183+
var cd = pcd.instantiate(dispatcher, [new BindingRecord(ast, "memo", "memo")]);
186184
cd.hydrate(new TestData("value"));
187185

188186
cd.detectChanges();
@@ -230,12 +228,13 @@ export function main() {
230228
describe("group changes", () => {
231229
it("should notify the dispatcher when a group of records changes", () => {
232230
var pcd = createProtoChangeDetector();
233-
pcd.addAst(ast("1 + 2"), "memo", "1");
234-
pcd.addAst(ast("10 + 20"), "memo", "1");
235-
pcd.addAst(ast("100 + 200"), "memo2", "2");
236231

237232
var dispatcher = new TestDispatcher();
238-
var cd = pcd.instantiate(dispatcher);
233+
var cd = pcd.instantiate(dispatcher, [
234+
new BindingRecord(ast("1 + 2"), "memo", "1"),
235+
new BindingRecord(ast("10 + 20"), "memo", "1"),
236+
new BindingRecord(ast("100 + 200"), "memo", "2")
237+
]);
239238

240239
cd.detectChanges();
241240

@@ -244,12 +243,12 @@ export function main() {
244243

245244
it("should notify the dispatcher before switching to the next group", () => {
246245
var pcd = createProtoChangeDetector();
247-
pcd.addAst(ast("a()"), "a", "1");
248-
pcd.addAst(ast("b()"), "b", "2");
249-
pcd.addAst(ast("c()"), "c", "2");
250-
251246
var dispatcher = new TestDispatcher();
252-
var cd = pcd.instantiate(dispatcher);
247+
var cd = pcd.instantiate(dispatcher, [
248+
new BindingRecord(ast("a()"), "a", "1"),
249+
new BindingRecord(ast("b()"), "b", "2"),
250+
new BindingRecord(ast("c()"), "c", "2")
251+
]);
253252

254253
var tr = new TestRecord();
255254
tr.a = () => {
@@ -279,7 +278,9 @@ export function main() {
279278
pcd.addAst(ast("a"), "a", 1);
280279

281280
var dispatcher = new TestDispatcher();
282-
var cd = pcd.instantiate(dispatcher);
281+
var cd = pcd.instantiate(dispatcher, [
282+
new BindingRecord(ast("a"), "a", 1)
283+
]);
283284
cd.hydrate(new TestData('value'));
284285

285286
expect(() => {
@@ -292,9 +293,9 @@ export function main() {
292293
describe("error handling", () => {
293294
xit("should wrap exceptions into ChangeDetectionError", () => {
294295
var pcd = createProtoChangeDetector();
295-
pcd.addAst(ast('invalidProp', 'someComponent'), "a", 1);
296-
297-
var cd = pcd.instantiate(new TestDispatcher());
296+
var cd = pcd.instantiate(new TestDispatcher(), [
297+
new BindingRecord(ast("invalidProp", "someComponent"), "a", 1)
298+
]);
298299
cd.hydrate(null);
299300

300301
try {
@@ -349,10 +350,10 @@ export function main() {
349350

350351
beforeEach(() => {
351352
var protoParent = createProtoChangeDetector();
352-
parent = protoParent.instantiate(null);
353+
parent = protoParent.instantiate(null, []);
353354

354355
var protoChild = createProtoChangeDetector();
355-
child = protoChild.instantiate(null);
356+
child = protoChild.instantiate(null, []);
356357
});
357358

358359
it("should add children", () => {
@@ -395,7 +396,7 @@ export function main() {
395396
});
396397

397398
it("should change CHECK_ONCE to CHECKED", () => {
398-
var cd = createProtoChangeDetector().instantiate(null);
399+
var cd = createProtoChangeDetector().instantiate(null, []);
399400
cd.mode = CHECK_ONCE;
400401

401402
cd.detectChanges();
@@ -404,7 +405,7 @@ export function main() {
404405
});
405406

406407
it("should not change the CHECK_ALWAYS", () => {
407-
var cd = createProtoChangeDetector().instantiate(null);
408+
var cd = createProtoChangeDetector().instantiate(null, []);
408409
cd.mode = CHECK_ALWAYS;
409410

410411
cd.detectChanges();
@@ -415,7 +416,7 @@ export function main() {
415416

416417
describe("markPathToRootAsCheckOnce", () => {
417418
function changeDetector(mode, parent) {
418-
var cd = createProtoChangeDetector().instantiate(null);
419+
var cd = createProtoChangeDetector().instantiate(null, []);
419420
cd.mode = mode;
420421
if (isPresent(parent)) parent.addChild(cd);
421422
return cd;

modules/angular2/test/core/compiler/element_injector_spec.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {NgElement} from 'angular2/src/core/dom/element';
1212
import {LightDom, DestinationLightDom} from 'angular2/src/core/compiler/shadow_dom_emulation/light_dom';
1313
import {Directive} from 'angular2/src/core/annotations/annotations';
1414
import {BindingPropagationConfig} from 'angular2/src/core/compiler/binding_propagation_config';
15-
import {DynamicProtoChangeDetector} from 'angular2/change_detection';
1615

1716
@proxy
1817
@IMPLEMENTS(View)
@@ -476,7 +475,7 @@ export function main() {
476475
StringMapWrapper.set(handlers, 'click', (e, view) => { called = true;});
477476
var pv = new ProtoView(null, null, null);
478477
pv.eventHandlers = [handlers];
479-
var view = new View(pv, null, new DynamicProtoChangeDetector(null), MapWrapper.create());
478+
var view = new View(pv, null, MapWrapper.create());
480479
var preBuildObject = new PreBuiltObjects(view, null, null, null, null);
481480
var inj = injector([NeedsEventEmitter], null, null, preBuildObject);
482481
inj.get(NeedsEventEmitter).click();

modules/angular2/test/core/compiler/view_container_spec.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ import {NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_str
1010
import {DynamicProtoChangeDetector, ChangeDetector, Lexer, Parser} from 'angular2/change_detection';
1111

1212
function createView(nodes) {
13-
var view = new View(null, nodes, new DynamicProtoChangeDetector(null), MapWrapper.create());
14-
view.init([], [], [], [], [], [], []);
13+
var view = new View(null, nodes, MapWrapper.create());
14+
var cd = new DynamicProtoChangeDetector(null).instantiate(view, []);
15+
view.init(cd, [], [], [], [], [], [], []);
1516
return view;
1617
}
1718

0 commit comments

Comments
 (0)