X Tutup
Skip to content

Commit ca09701

Browse files
committed
perf(render): only create LightDom instances if the element has children
1 parent 4f27611 commit ca09701

File tree

5 files changed

+59
-12
lines changed

5 files changed

+59
-12
lines changed

modules/angular2/src/render/dom/dom_renderer.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -276,11 +276,15 @@ export class DomRenderer extends Renderer {
276276
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
277277
var binder = binders[binderIdx];
278278
var element = boundElements[binderIdx];
279+
var domEl = element.element;
279280

280281
// lightDoms
281282
var lightDom = null;
282-
if (isPresent(binder.componentId)) {
283-
lightDom = this._shadowDomStrategy.constructLightDom(view, element.element);
283+
// Note: for the root element we can't use the binder.elementIsEmpty
284+
// information as we don't use the element from the ProtoView
285+
// but an element from the document.
286+
if (isPresent(binder.componentId) && (!binder.elementIsEmpty || isPresent(inplaceElement))) {
287+
lightDom = this._shadowDomStrategy.constructLightDom(view, domEl);
284288
}
285289
element.lightDom = lightDom;
286290

@@ -294,7 +298,7 @@ export class DomRenderer extends Renderer {
294298
// events
295299
if (isPresent(binder.eventLocals) && isPresent(binder.localEvents)) {
296300
for (var i = 0; i < binder.localEvents.length; i++) {
297-
this._createEventListener(view, element.element, binderIdx, binder.localEvents[i].name,
301+
this._createEventListener(view, domEl, binderIdx, binder.localEvents[i].name,
298302
binder.eventLocals);
299303
}
300304
}

modules/angular2/src/render/dom/view/element_binder.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@ export class ElementBinder {
1515
distanceToParent: number;
1616
propertySetters: Map<string, SetterFn>;
1717
hostActions: Map<string, AST>;
18+
elementIsEmpty: boolean;
1819

1920
constructor({textNodeIndices, contentTagSelector, nestedProtoView, componentId, eventLocals,
2021
localEvents, globalEvents, hostActions, parentIndex, distanceToParent,
21-
propertySetters}: {
22+
propertySetters, elementIsEmpty}: {
2223
contentTagSelector?: string,
2324
textNodeIndices?: List<number>,
2425
nestedProtoView?: protoViewModule.DomProtoView,
@@ -29,7 +30,8 @@ export class ElementBinder {
2930
parentIndex?: number,
3031
distanceToParent?: number,
3132
propertySetters?: Map<string, SetterFn>,
32-
hostActions?: Map<string, AST>
33+
hostActions?: Map<string, AST>,
34+
elementIsEmpty?: boolean
3335
} = {}) {
3436
this.textNodeIndices = textNodeIndices;
3537
this.contentTagSelector = contentTagSelector;
@@ -42,6 +44,7 @@ export class ElementBinder {
4244
this.parentIndex = parentIndex;
4345
this.distanceToParent = distanceToParent;
4446
this.propertySetters = propertySetters;
47+
this.elementIsEmpty = elementIsEmpty;
4548
}
4649
}
4750

modules/angular2/src/render/dom/view/proto_view_builder.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ export class ProtoViewBuilder {
5757

5858
MapWrapper.forEach(dbb.hostPropertyBindings, (_, hostPropertyName) => {
5959
MapWrapper.set(propertySetters, hostPropertyName,
60-
setterFactory.createSetter(ebb.element, isPresent(ebb.componentId), hostPropertyName));
60+
setterFactory.createSetter(ebb.element, isPresent(ebb.componentId),
61+
hostPropertyName));
6162
});
6263

6364
ListWrapper.forEach(dbb.hostActions, (hostAction) => {
@@ -73,7 +74,9 @@ export class ProtoViewBuilder {
7374
});
7475

7576
MapWrapper.forEach(ebb.propertyBindings, (_, propertyName) => {
76-
MapWrapper.set(propertySetters, propertyName, setterFactory.createSetter(ebb.element, isPresent(ebb.componentId), propertyName));
77+
MapWrapper.set(
78+
propertySetters, propertyName,
79+
setterFactory.createSetter(ebb.element, isPresent(ebb.componentId), propertyName));
7780
});
7881

7982
var nestedProtoView =
@@ -99,6 +102,7 @@ export class ProtoViewBuilder {
99102
textBindings: ebb.textBindings,
100103
readAttributes: ebb.readAttributes
101104
}));
105+
var elementIsEmpty = this._isEmptyElement(ebb.element);
102106
ListWrapper.push(renderElementBinders, new ElementBinder({
103107
textNodeIndices: ebb.textBindingIndices,
104108
contentTagSelector: ebb.contentTagSelector,
@@ -112,7 +116,8 @@ export class ProtoViewBuilder {
112116
localEvents: ebb.eventBuilder.buildLocalEvents(),
113117
globalEvents: ebb.eventBuilder.buildGlobalEvents(),
114118
hostActions: hostActions,
115-
propertySetters: propertySetters
119+
propertySetters: propertySetters,
120+
elementIsEmpty: elementIsEmpty
116121
}));
117122
});
118123
return new api.ProtoViewDto({
@@ -126,6 +131,18 @@ export class ProtoViewBuilder {
126131
variableBindings: this.variableBindings
127132
});
128133
}
134+
135+
_isEmptyElement(el) {
136+
var childNodes = DOM.childNodes(el);
137+
for (var i = 0; i < childNodes.length; i++) {
138+
var node = childNodes[i];
139+
if ((DOM.isTextNode(node) && DOM.getText(node).trim().length > 0) ||
140+
(DOM.isElementNode(node))) {
141+
return false;
142+
}
143+
}
144+
return true;
145+
}
129146
}
130147

131148
export class ElementBinderBuilder {

modules/angular2/test/render/dom/dom_renderer_integration_spec.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,25 @@ export function main() {
7070
});
7171
}));
7272

73+
it('should not create LightDom instances if the host element is empty',
74+
inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
75+
tb.compileAll([
76+
someComponent,
77+
new ViewDefinition({
78+
componentId: 'someComponent', template: '<some-comp> <!-- comment -->\n </some-comp>',
79+
directives: [someComponent]
80+
})
81+
])
82+
.then((protoViewDtos) => {
83+
var rootView = tb.createRootView(protoViewDtos[0]);
84+
var cmpView = tb.createComponentView(rootView.viewRef, 0, protoViewDtos[1]);
85+
expect(cmpView.rawView.proto.elementBinders[0].componentId).toBe('someComponent');
86+
expect(cmpView.rawView.boundElements[0].lightDom).toBe(null);
87+
88+
async.done();
89+
});
90+
}));
91+
7392
it('should update text nodes', inject([AsyncTestCompleter, DomTestbed], (async, tb) => {
7493
tb.compileAll([
7594
someComponent,

modules/angular2/test/render/dom/view/view_spec.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,20 +48,24 @@ export function main() {
4848
return new DomView(pv, [DOM.childNodes(root)[0]], [], boundElements);
4949
}
5050

51+
function createElementBinder(parentIndex:number = 0, distanceToParent:number = 1) {
52+
return new ElementBinder({parentIndex: parentIndex, distanceToParent:distanceToParent, textNodeIndices:[]});
53+
}
54+
5155
describe('getDirectParentElement', () => {
5256

5357
it('should return the DomElement of the direct parent', () => {
5458
var pv = createProtoView(
55-
[new ElementBinder(), new ElementBinder({parentIndex: 0, distanceToParent: 1})]);
59+
[createElementBinder(), createElementBinder(0, 1)]);
5660
var view = createView(pv, 2);
5761
expect(view.getDirectParentElement(1)).toBe(view.boundElements[0]);
5862
});
5963

6064
it('should return null if the direct parent is not bound', () => {
6165
var pv = createProtoView([
62-
new ElementBinder(),
63-
new ElementBinder(),
64-
new ElementBinder({parentIndex: 0, distanceToParent: 2})
66+
createElementBinder(),
67+
createElementBinder(),
68+
createElementBinder(0,2)
6569
]);
6670
var view = createView(pv, 3);
6771
expect(view.getDirectParentElement(2)).toBe(null);

0 commit comments

Comments
 (0)
X Tutup