Skip to content
This repository was archived by the owner on Feb 22, 2018. It is now read-only.

Commit 00960bb

Browse files
mheveryrkirov
authored andcommitted
perf(view): increase view instantiation speed 40%
1) Stop using futures when the value is already cached 2) Remove adding nodes to fake parent during view instantiation Closes #1358
1 parent 97410f7 commit 00960bb

12 files changed

+271
-184
lines changed

lib/core_dom/directive.dart

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class NodeAttrs {
2222

2323
NodeAttrs(this.element);
2424

25-
operator [](String attrName) => element.attributes[attrName];
25+
operator [](String attrName) => element.getAttribute(attrName);
2626

2727
void operator []=(String attrName, String value) {
2828
if (_mustacheAttrs.containsKey(attrName)) {
@@ -31,7 +31,7 @@ class NodeAttrs {
3131
if (value == null) {
3232
element.attributes.remove(attrName);
3333
} else {
34-
element.attributes[attrName] = value;
34+
element.setAttribute(attrName, value);
3535
}
3636

3737
if (_observers != null && _observers.containsKey(attrName)) {
@@ -86,9 +86,18 @@ class NodeAttrs {
8686
* ShadowRoot is ready.
8787
*/
8888
class TemplateLoader {
89-
final async.Future<dom.Node> template;
89+
async.Future<dom.Node> _template;
90+
List<async.Future> _futures;
91+
final dom.Node _shadowRoot;
9092

91-
TemplateLoader(this.template);
93+
TemplateLoader(this._shadowRoot, this._futures);
94+
95+
async.Future<dom.Node> get template {
96+
if (_template == null) {
97+
_template = async.Future.wait(_futures).then((_) => _shadowRoot);
98+
}
99+
return _template;
100+
}
92101
}
93102

94103
class _MustacheAttr {

lib/core_dom/shadow_boundary.dart

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,29 @@ part of angular.core.dom_internal;
77
*/
88
abstract class ShadowBoundary {
99
Set<dom.StyleElement> _insertedStyles;
10+
final dom.Node root;
11+
dom.StyleElement _lastStyleElement;
12+
13+
ShadowBoundary(this.root);
1014

11-
void insertStyleElements(List<dom.StyleElement> elements);
15+
void insertStyleElements(List<dom.StyleElement> elements, {bool prepend: false}) {
16+
if (elements.isEmpty) return;
17+
18+
final newStyles = _newStyles(elements);
19+
final cloned = newStyles.map((el) => el.clone(true));
20+
21+
cloned.forEach((style) {
22+
if (_lastStyleElement != null && !prepend) {
23+
_lastStyleElement = root.insertBefore(style, _lastStyleElement.nextNode);
24+
} else if (root.hasChildNodes()) {
25+
_lastStyleElement = root.insertBefore(style, root.firstChild);
26+
} else {
27+
_lastStyleElement = root.append(style);
28+
}
29+
});
30+
31+
_addInsertedStyles(newStyles);
32+
}
1233

1334
Iterable<dom.StyleElement> _newStyles(Iterable<dom.StyleElement> elements) {
1435
if (_insertedStyles == null) return elements;
@@ -23,37 +44,15 @@ abstract class ShadowBoundary {
2344

2445
@Injectable()
2546
class DefaultShadowBoundary extends ShadowBoundary {
26-
void insertStyleElements(List<dom.StyleElement> elements) {
27-
final newStyles = _newStyles(elements);
28-
final cloned = newStyles.map((el) => el.clone(true));
29-
dom.document.head.nodes.addAll(cloned);
30-
_addInsertedStyles(newStyles);
31-
}
47+
DefaultShadowBoundary()
48+
: super(dom.document.head);
49+
50+
DefaultShadowBoundary.custom(dom.Node node)
51+
: super(node);
3252
}
3353

3454
@Injectable()
3555
class ShadowRootBoundary extends ShadowBoundary {
36-
final dom.ShadowRoot shadowRoot;
37-
dom.StyleElement _lastStyleElement;
38-
39-
ShadowRootBoundary(this.shadowRoot);
40-
41-
void insertStyleElements(List<dom.StyleElement> elements) {
42-
if (elements.isEmpty) return;
43-
44-
final newStyles = _newStyles(elements);
45-
final cloned = newStyles.map((el) => el.clone(true));
46-
47-
cloned.forEach((style) {
48-
if (_lastStyleElement != null) {
49-
_lastStyleElement = shadowRoot.insertBefore(style, _lastStyleElement.nextNode);
50-
} else if (shadowRoot.hasChildNodes()) {
51-
_lastStyleElement = shadowRoot.insertBefore(style, shadowRoot.firstChild);
52-
} else {
53-
_lastStyleElement = shadowRoot.append(style);
54-
}
55-
});
56-
57-
_addInsertedStyles(newStyles);
58-
}
56+
ShadowRootBoundary(dom.ShadowRoot shadowRoot)
57+
: super(shadowRoot);
5958
}

lib/core_dom/shadow_dom_component_factory.dart

Lines changed: 68 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@ abstract class BoundComponentFactory {
1111
List<Key> get callArgs;
1212
Function call(dom.Element element);
1313

14-
static async.Future<ViewFactory> _viewFuture(
14+
static async.Future<ViewFactory> _viewFactoryFuture(
1515
Component component, ViewCache viewCache, DirectiveMap directives,
1616
TypeToUriMapper uriMapper, ResourceUrlResolver resourceResolver, Type type) {
17-
1817
if (component.template != null) {
1918
// TODO(chirayu): Replace this line with
2019
// var baseUri = uriMapper.uriForType(type);
@@ -77,71 +76,95 @@ class BoundShadowDomComponentFactory implements BoundComponentFactory {
7776
Component get _component => _ref.annotation as Component;
7877

7978
String _tag;
80-
async.Future<Iterable<dom.StyleElement>> _styleElementsFuture;
81-
async.Future<ViewFactory> _viewFuture;
79+
async.Future<List<dom.StyleElement>> _styleElementsFuture;
80+
List<dom.StyleElement> _styleElements;
81+
async.Future<ViewFactory> _shadowViewFactoryFuture;
82+
ViewFactory _shadowViewFactory;
8283

8384
BoundShadowDomComponentFactory(this._componentFactory, this._ref,
8485
DirectiveMap directives, this._injector) {
8586
_tag = _ref.annotation.selector.toLowerCase();
86-
_styleElementsFuture = _componentFactory.cssLoader(_tag, _component.cssUrls, type: _ref.type);
87+
_styleElementsFuture = _componentFactory.cssLoader(_tag, _component.cssUrls, type: _ref.type)
88+
.then((styleElements) => _styleElements = styleElements);
8789

8890
final viewCache = new ShimmingViewCache(_componentFactory.viewCache,
8991
_tag, _componentFactory.platformShim);
90-
_viewFuture = BoundComponentFactory._viewFuture(_component, viewCache, directives,
91-
_componentFactory.uriMapper, _componentFactory.resourceResolver, _ref.type);
92+
93+
_shadowViewFactoryFuture = BoundComponentFactory._viewFactoryFuture(_component,
94+
viewCache, directives, _componentFactory.uriMapper,
95+
_componentFactory.resourceResolver, _ref.type);
96+
97+
if (_shadowViewFactoryFuture != null) {
98+
_shadowViewFactoryFuture.then((viewFactory) => _shadowViewFactory = viewFactory);
99+
}
92100
}
93101

94102
List<Key> get callArgs => _CALL_ARGS;
95103
static final _CALL_ARGS = [DIRECTIVE_INJECTOR_KEY, SCOPE_KEY, VIEW_KEY, NG_BASE_CSS_KEY,
96104
SHADOW_BOUNDARY_KEY];
105+
97106
Function call(dom.Element element) {
98107
return (DirectiveInjector injector, Scope scope, View view, NgBaseCss baseCss,
99108
ShadowBoundary parentShadowBoundary) {
100109
var s = traceEnter(View_createComponent);
101110
try {
102-
var shadowDom = element.createShadowRoot();
111+
var shadowRoot = element.createShadowRoot();
103112

104113
var shadowBoundary;
105114
if (_componentFactory.platformShim.shimRequired) {
106115
shadowBoundary = parentShadowBoundary;
107116
} else {
108-
shadowBoundary = new ShadowRootBoundary(shadowDom);
117+
shadowBoundary = new ShadowRootBoundary(shadowRoot);
109118
}
110119

111-
//_styleFuture(cssUrl, resolveUri: false)
112120
var shadowScope = scope.createChild(new HashMap()); // Isolate
113-
ComponentDirectiveInjector shadowInjector;
114-
115-
final baseUrls = (_component.useNgBaseCss) ? baseCss.urls : [];
116-
final baseUrlsFuture = _componentFactory.cssLoader(_tag, baseUrls);
117-
final cssFuture = mergeFutures(baseUrlsFuture, _styleElementsFuture);
118-
119-
async.Future<dom.Node> initShadowDom(_) {
120-
if (_viewFuture == null) return new async.Future.value(shadowDom);
121-
return _viewFuture.then((ViewFactory viewFactory) {
122-
if (shadowScope.isAttached) {
123-
shadowDom.nodes.addAll(
124-
viewFactory.call(shadowInjector.scope, shadowInjector).nodes);
125-
}
126-
return shadowDom;
127-
});
128-
}
129-
130-
TemplateLoader templateLoader = new TemplateLoader(
131-
cssFuture.then(shadowBoundary.insertStyleElements).then(initShadowDom));
121+
List<async.Future> futures = <async.Future>[];
122+
TemplateLoader templateLoader = new TemplateLoader(shadowRoot, futures);
132123

133124
var probe;
134125
var eventHandler = new ShadowRootEventHandler(
135-
shadowDom, injector.getByKey(EXPANDO_KEY), injector.getByKey(EXCEPTION_HANDLER_KEY));
136-
shadowInjector = new ComponentDirectiveInjector(injector, _injector, eventHandler, shadowScope,
137-
templateLoader, shadowDom, null, view, shadowBoundary);
126+
shadowRoot, injector.getByKey(EXPANDO_KEY), injector.getByKey(EXCEPTION_HANDLER_KEY));
127+
final shadowInjector = new ComponentDirectiveInjector(injector, _injector, eventHandler, shadowScope,
128+
templateLoader, shadowRoot, null, view, shadowBoundary);
129+
shadowInjector.bindByKey(_ref.typeKey, _ref.factory, _ref.paramKeys, _ref.annotation.visibility);
138130

131+
if (_component.useNgBaseCss && baseCss.urls.isNotEmpty) {
132+
if (baseCss.styles == null) {
133+
final f = _componentFactory.cssLoader(_tag, baseCss.urls).then((cssList) {
134+
baseCss.styles = cssList;
135+
shadowBoundary.insertStyleElements(cssList, prepend: true);
136+
});
137+
futures.add(f);
138+
} else {
139+
shadowBoundary.insertStyleElements(baseCss.styles, prepend: true);
140+
}
141+
}
139142

140-
shadowInjector.bindByKey(_ref.typeKey, _ref.factory, _ref.paramKeys, _ref.annotation.visibility);
143+
if (_styleElementsFuture != null) {
144+
if (_styleElements == null) {
145+
final f = _styleElementsFuture.then(shadowBoundary.insertStyleElements);
146+
futures.add(f);
147+
} else {
148+
shadowBoundary.insertStyleElements(_styleElements);
149+
}
150+
}
151+
152+
if (_shadowViewFactoryFuture != null) {
153+
if (_shadowViewFactory == null) {
154+
final f = _shadowViewFactoryFuture.then((ViewFactory viewFactory) =>
155+
_insertView(viewFactory, shadowRoot, shadowScope, shadowInjector));
156+
futures.add(f);
157+
} else {
158+
final f = new Future.microtask(() {
159+
_insertView(_shadowViewFactory, shadowRoot, shadowScope, shadowInjector);
160+
});
161+
futures.add(f);
162+
}
163+
}
141164

142165
if (_componentFactory.config.elementProbeEnabled) {
143-
probe = _componentFactory.expando[shadowDom] = shadowInjector.elementProbe;
144-
shadowScope.on(ScopeEvent.DESTROY).listen((ScopeEvent) => _componentFactory.expando[shadowDom] = null);
166+
ElementProbe probe = _componentFactory.expando[shadowRoot] = shadowInjector.elementProbe;
167+
shadowScope.on(ScopeEvent.DESTROY).listen((ScopeEvent) => _componentFactory.expando[shadowRoot] = null);
145168
}
146169

147170
var controller = shadowInjector.getByKey(_ref.typeKey);
@@ -155,6 +178,16 @@ class BoundShadowDomComponentFactory implements BoundComponentFactory {
155178
}
156179
};
157180
}
181+
182+
dom.Node _insertView(ViewFactory viewFactory,
183+
dom.ShadowRoot shadowRoot,
184+
Scope shadowScope,
185+
ComponentDirectiveInjector shadowInjector) {
186+
if (shadowScope.isAttached) {
187+
shadowRoot.nodes.addAll(
188+
viewFactory.call(shadowInjector.scope, shadowInjector).nodes);
189+
}
190+
}
158191
}
159192

160193
@Injectable()

0 commit comments

Comments
 (0)