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

Commit af906c9

Browse files
committed
Revert "perf(view): increase view instantiation speed 40%"
This reverts commit f20eab2 as it breaks some applications. We need to write test cases for the failures and do one or both of: (1) fixup the PR 1358, (2) specify the breaking changes so that applications can be upgraded.
1 parent 5929a23 commit af906c9

File tree

9 files changed

+113
-171
lines changed

9 files changed

+113
-171
lines changed

lib/core_dom/directive.dart

Lines changed: 4 additions & 13 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.getAttribute(attrName);
25+
operator [](String attrName) => element.attributes[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.setAttribute(attrName, value);
34+
element.attributes[attrName] = value;
3535
}
3636

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

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-
}
91+
TemplateLoader(this.template);
10192
}
10293

10394
class _MustacheAttr {

lib/core_dom/shadow_dom_component_factory.dart

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

14-
static async.Future<ViewFactory> _viewFactoryFuture(
14+
static async.Future<ViewFactory> _viewFuture(
1515
Component component, ViewCache viewCache, DirectiveMap directives) {
1616
if (component.template != null) {
1717
return new async.Future.value(viewCache.fromHtml(component.template, directives));
@@ -65,27 +65,20 @@ class BoundShadowDomComponentFactory implements BoundComponentFactory {
6565
Component get _component => _ref.annotation as Component;
6666

6767
String _tag;
68-
async.Future<List<dom.StyleElement>> _styleElementsFuture;
69-
List<dom.StyleElement> _styleElements;
70-
async.Future<ViewFactory> _shadowViewFactoryFuture;
71-
ViewFactory _shadowViewFactory;
68+
async.Future<Iterable<dom.StyleElement>> _styleElementsFuture;
69+
async.Future<ViewFactory> _viewFuture;
7270

7371
BoundShadowDomComponentFactory(this._componentFactory, this._ref, this._directives) {
7472
_tag = _component.selector.toLowerCase();
75-
_styleElementsFuture = async.Future.wait(_component.cssUrls.map(_urlToStyle))
76-
..then((stylesElements) => _styleElements = stylesElements);
73+
_styleElementsFuture = async.Future.wait(_component.cssUrls.map(_styleFuture));
7774

78-
_shadowViewFactoryFuture = BoundComponentFactory._viewFactoryFuture(
75+
_viewFuture = BoundComponentFactory._viewFuture(
7976
_component,
80-
// TODO(misko): Why do we create a new one per Component. This kind of defeats the caching.
8177
new PlatformViewCache(_componentFactory.viewCache, _tag, _componentFactory.platform),
8278
_directives);
83-
if (_shadowViewFactoryFuture != null) {
84-
_shadowViewFactoryFuture.then((viewFactory) => _shadowViewFactory = viewFactory);
85-
}
8679
}
8780

88-
async.Future<dom.StyleElement> _urlToStyle(cssUrl) {
81+
async.Future<dom.StyleElement> _styleFuture(cssUrl) {
8982
Http http = _componentFactory.http;
9083
TemplateCache templateCache = _componentFactory.templateCache;
9184
WebPlatform platform = _componentFactory.platform;
@@ -114,7 +107,7 @@ class BoundShadowDomComponentFactory implements BoundComponentFactory {
114107

115108
// If the css shim is required, it means that scoping does not
116109
// work, and adding the style to the head of the document is
117-
// preferable.
110+
// preferrable.
118111
if (platform.cssShimRequired) {
119112
dom.document.head.append(styleElement);
120113
return null;
@@ -133,57 +126,47 @@ class BoundShadowDomComponentFactory implements BoundComponentFactory {
133126
EventHandler eventHandler) {
134127
var s = traceEnter(View_createComponent);
135128
try {
136-
var shadowScope = scope.createChild(new HashMap()); // Isolate
137-
ComponentDirectiveInjector shadowInjector;
138-
dom.ShadowRoot shadowRoot = element.createShadowRoot();
139-
shadowRoot
129+
var shadowDom = element.createShadowRoot()
140130
..applyAuthorStyles = _component.applyAuthorStyles
141131
..resetStyleInheritance = _component.resetStyleInheritance;
142132

143-
List<async.Future> futures = <async.Future>[];
144-
TemplateLoader templateLoader = new TemplateLoader(shadowRoot, futures);
145-
shadowInjector = new ShadowDomComponentDirectiveInjector(
146-
injector, injector.appInjector, shadowScope, templateLoader, shadowRoot);
147-
shadowInjector.bindByKey(_ref.typeKey, _ref.factory, _ref.paramKeys,
148-
_ref.annotation.visibility);
149-
dom.Node firstViewNode = null;
150-
151-
// Load ngBase CSS
152-
if (_component.useNgBaseCss == true && baseCss.urls.isNotEmpty) {
153-
if (baseCss.styles == null) {
154-
futures.add(async.Future
155-
.wait(baseCss.urls.map(_urlToStyle))
156-
.then((List<dom.StyleElement> cssList) {
157-
baseCss.styles = cssList;
158-
_insertCss(cssList, shadowRoot, shadowRoot.firstChild);
159-
}));
160-
} else {
161-
_insertCss(baseCss.styles, shadowRoot, shadowRoot.firstChild);
162-
}
163-
}
133+
var shadowScope = scope.createChild(new HashMap()); // Isolate
164134

165-
if (_styleElementsFuture != null) {
166-
if (_styleElements == null) {
167-
futures.add(_styleElementsFuture .then((List<dom.StyleElement> styles) =>
168-
_insertCss(styles, shadowRoot, firstViewNode)));
169-
} else {
170-
_insertCss(_styleElements, shadowRoot);
171-
}
135+
async.Future<Iterable<dom.StyleElement>> cssFuture;
136+
if (_component.useNgBaseCss == true) {
137+
cssFuture = async.Future.wait([async.Future.wait(baseCss.urls.map(_styleFuture)), _styleElementsFuture]).then((twoLists) {
138+
assert(twoLists.length == 2);return []
139+
..addAll(twoLists[0])
140+
..addAll(twoLists[1]);
141+
});
142+
} else {
143+
cssFuture = _styleElementsFuture;
172144
}
173145

146+
ComponentDirectiveInjector shadowInjector;
174147

175-
if (_shadowViewFactoryFuture != null) {
176-
if (_shadowViewFactory == null) {
177-
futures.add(_shadowViewFactoryFuture.then((ViewFactory viewFactory) =>
178-
firstViewNode = _insertView(viewFactory, shadowRoot, shadowScope, shadowInjector)));
179-
} else {
180-
_insertView(_shadowViewFactory, shadowRoot, shadowScope, shadowInjector);
148+
TemplateLoader templateLoader = new TemplateLoader(cssFuture.then((Iterable<dom.StyleElement> cssList) {
149+
cssList.where((styleElement) => styleElement != null).forEach((styleElement) {
150+
shadowDom.append(styleElement.clone(true));
151+
});
152+
if (_viewFuture != null) {
153+
return _viewFuture.then((ViewFactory viewFactory) {
154+
if (shadowScope.isAttached) {
155+
shadowDom.nodes.addAll(viewFactory.call(shadowInjector.scope, shadowInjector).nodes);
156+
}
157+
return shadowDom;
158+
});
181159
}
182-
}
160+
return shadowDom;
161+
}));
162+
163+
var probe;
164+
shadowInjector = new ShadowDomComponentDirectiveInjector(injector, injector.appInjector, shadowScope, templateLoader, shadowDom);
165+
shadowInjector.bindByKey(_ref.typeKey, _ref.factory, _ref.paramKeys, _ref.annotation.visibility);
183166

184167
if (_componentFactory.config.elementProbeEnabled) {
185-
ElementProbe probe = _componentFactory.expando[shadowRoot] = shadowInjector.elementProbe;
186-
shadowScope.on(ScopeEvent.DESTROY).listen((ScopeEvent) => _componentFactory.expando[shadowRoot] = null);
168+
probe = _componentFactory.expando[shadowDom] = shadowInjector.elementProbe;
169+
shadowScope.on(ScopeEvent.DESTROY).listen((ScopeEvent) => _componentFactory.expando[shadowDom] = null);
187170
}
188171

189172
var controller = shadowInjector.getByKey(_ref.typeKey);
@@ -197,36 +180,6 @@ class BoundShadowDomComponentFactory implements BoundComponentFactory {
197180
}
198181
};
199182
}
200-
201-
_insertCss(List<dom.StyleElement> cssList,
202-
dom.ShadowRoot shadowRoot,
203-
[dom.Node insertBefore = null]) {
204-
var s = traceEnter(View_styles);
205-
for(int i = 0; i < cssList.length; i++) {
206-
var styleElement = cssList[i];
207-
if (styleElement != null) {
208-
shadowRoot.insertBefore(styleElement.clone(true), insertBefore);
209-
}
210-
}
211-
traceLeave(s);
212-
}
213-
214-
dom.Node _insertView(ViewFactory viewFactory,
215-
dom.ShadowRoot shadowRoot,
216-
Scope shadowScope,
217-
ShadowDomComponentDirectiveInjector shadowInjector) {
218-
dom.Node first = null;
219-
if (shadowScope.isAttached) {
220-
View shadowView = viewFactory.call(shadowScope, shadowInjector);
221-
List<dom.Node> shadowViewNodes = shadowView.nodes;
222-
for (var j = 0; j < shadowViewNodes.length; j++) {
223-
var node = shadowViewNodes[j];
224-
if (j == 0) first = node;
225-
shadowRoot.append(node);
226-
}
227-
}
228-
return first;
229-
}
230183
}
231184

232185
class _ComponentAssetKey {

lib/core_dom/transcluding_component_factory.dart

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,13 @@ class BoundTranscludingComponentFactory implements BoundComponentFactory {
8787
final DirectiveMap _directives;
8888

8989
Component get _component => _ref.annotation as Component;
90-
async.Future<ViewFactory> _viewFactoryFuture;
91-
ViewFactory _viewFactory;
90+
async.Future<ViewFactory> _viewFuture;
9291

9392
BoundTranscludingComponentFactory(this._f, this._ref, this._directives) {
94-
_viewFactoryFuture = BoundComponentFactory._viewFactoryFuture(_component, _f.viewCache, _directives);
95-
if (_viewFactoryFuture != null) {
96-
_viewFactoryFuture.then((viewFactory) => _viewFactory = viewFactory);
97-
}
93+
_viewFuture = BoundComponentFactory._viewFuture(
94+
_component,
95+
_f.viewCache,
96+
_directives);
9897
}
9998

10099
List<Key> get callArgs => _CALL_ARGS;
@@ -111,40 +110,52 @@ class BoundTranscludingComponentFactory implements BoundComponentFactory {
111110
ViewCache viewCache, Http http, TemplateCache templateCache,
112111
DirectiveMap directives, NgBaseCss baseCss, EventHandler eventHandler) {
113112

114-
List<async.Future> futures = [];
113+
DirectiveInjector childInjector;
114+
var childInjectorCompleter; // Used if the ViewFuture is available before the childInjector.
115+
116+
var component = _component;
115117
var contentPort = new ContentPort(element);
116-
TemplateLoader templateLoader = new TemplateLoader(element, futures);
118+
119+
// Append the component's template as children
120+
var elementFuture;
121+
122+
if (_viewFuture != null) {
123+
elementFuture = _viewFuture.then((ViewFactory viewFactory) {
124+
contentPort.pullNodes();
125+
if (childInjector != null) {
126+
element.nodes.addAll(
127+
viewFactory.call(childInjector.scope, childInjector).nodes);
128+
return element;
129+
} else {
130+
childInjectorCompleter = new async.Completer();
131+
return childInjectorCompleter.future.then((childInjector) {
132+
element.nodes.addAll(
133+
viewFactory.call(childInjector.scope, childInjector).nodes);
134+
return element;
135+
});
136+
}
137+
});
138+
} else {
139+
elementFuture = new async.Future.microtask(() => contentPort.pullNodes());
140+
}
141+
TemplateLoader templateLoader = new TemplateLoader(elementFuture);
142+
117143
Scope shadowScope = scope.createChild(new HashMap());
118-
DirectiveInjector childInjector = new ShadowlessComponentDirectiveInjector(
119-
injector, injector.appInjector, eventHandler, shadowScope, templateLoader,
120-
new ShadowlessShadowRoot(element), contentPort);
144+
145+
childInjector = new ShadowlessComponentDirectiveInjector(injector, injector.appInjector,
146+
eventHandler, shadowScope, templateLoader, new ShadowlessShadowRoot(element),
147+
contentPort);
121148
childInjector.bindByKey(_ref.typeKey, _ref.factory, _ref.paramKeys, _ref.annotation.visibility);
122149

150+
if (childInjectorCompleter != null) {
151+
childInjectorCompleter.complete(childInjector);
152+
}
153+
123154
var controller = childInjector.getByKey(_ref.typeKey);
124-
shadowScope.context[_component.publishAs] = controller;
155+
shadowScope.context[component.publishAs] = controller;
125156
if (controller is ScopeAware) controller.scope = shadowScope;
126157
BoundComponentFactory._setupOnShadowDomAttach(controller, templateLoader, shadowScope);
127-
128-
if (_viewFactoryFuture != null && _viewFactory == null) {
129-
futures.add(_viewFactoryFuture.then((ViewFactory viewFactory) =>
130-
_insert(viewFactory, element, childInjector, contentPort)));
131-
} else {
132-
scope.rootScope.runAsync(() {
133-
_insert(_viewFactory, element, childInjector, contentPort);
134-
});
135-
}
136158
return controller;
137159
};
138160
}
139-
140-
_insert(ViewFactory viewFactory, dom.Element element, DirectiveInjector childInjector,
141-
ContentPort contentPort) {
142-
contentPort.pullNodes();
143-
if (viewFactory != null) {
144-
var viewNodes = viewFactory.call(childInjector.scope, childInjector).nodes;
145-
for(var i = 0; i < viewNodes.length; i++) {
146-
element.append(viewNodes[i]);
147-
}
148-
}
149-
}
150161
}

lib/core_dom/view_factory.dart

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,10 @@ class ViewFactory implements Function {
8989
}
9090
elementInjectors[elementBinderIndex] = elementInjector;
9191

92-
var textBinders = tagged.textBinders;
93-
if (textBinders != null && textBinders.length > 0) {
94-
var childNodes = boundNode.childNodes;
95-
for (var k = 0; k < textBinders.length; k++) {
96-
TaggedTextBinder taggedText = textBinders[k];
97-
var childNode = childNodes[taggedText.offsetIndex];
92+
if (tagged.textBinders != null) {
93+
for (var k = 0; k < tagged.textBinders.length; k++) {
94+
TaggedTextBinder taggedText = tagged.textBinders[k];
95+
var childNode = boundNode.childNodes[taggedText.offsetIndex];
9896
taggedText.binder.bind(view, scope, elementInjector, childNode, eventHandler, animate);
9997
}
10098
}
@@ -110,6 +108,15 @@ class ViewFactory implements Function {
110108
dom.Node node = nodeList[i];
111109
NodeLinkingInfo linkingInfo = nodeLinkingInfos[i];
112110

111+
// if node isn't attached to the DOM, create a parent for it.
112+
var parentNode = node.parentNode;
113+
var fakeParent = false;
114+
if (parentNode == null) {
115+
fakeParent = true;
116+
parentNode = new dom.DivElement();
117+
parentNode.append(node);
118+
}
119+
113120
if (linkingInfo.isElement) {
114121
if (linkingInfo.containsNgBinding) {
115122
var tagged = elementBinders[elementBinderIndex];
@@ -135,6 +142,11 @@ class ViewFactory implements Function {
135142
}
136143
elementBinderIndex++;
137144
}
145+
146+
if (fakeParent) {
147+
// extract the node from the parentNode.
148+
nodeList[i] = parentNode.nodes[0];
149+
}
138150
}
139151
return view;
140152
}

lib/core_dom/web_platform.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class WebPlatform {
4242
//
4343
// TODO Remove the try-catch once https://github.com/angular/angular.dart/issues/1189 is fixed.
4444
try {
45-
root.querySelectorAll("*").forEach((dom.Element n) => n.setAttribute(selector, ""));
45+
root.querySelectorAll("*").forEach((n) => n.attributes[selector] = "");
4646
} catch (e, s) {
4747
print("WARNING: Failed to set up Shadow DOM shim for $selector.\n$e\n$s");
4848
}
@@ -69,7 +69,6 @@ class PlatformViewCache implements ViewCache {
6969
if (selector != null && selector != "" && platform.shadowDomShimRequired) {
7070
// By adding a comment with the tag name we ensure the template html is unique per selector
7171
// name when used as a key in the view factory cache.
72-
//TODO(misko): This will always be miss, since we never put it in cache under such key.
7372
viewFactory = viewFactoryCache.get("<!-- Shimmed template for: <$selector> -->$html");
7473
} else {
7574
viewFactory = viewFactoryCache.get(html);

lib/directive/ng_base_css.dart

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,10 @@ part of angular.directive;
1212
selector: '[ng-base-css]',
1313
visibility: Visibility.CHILDREN)
1414
class NgBaseCss {
15-
List<dom.StyleElement> styles;
1615
List<String> _urls = const [];
1716

1817
@NgAttr('ng-base-css')
19-
set urls(v) {
20-
_urls = v is List ? v : [v];
21-
styles = null;
22-
}
18+
set urls(v) => _urls = v is List ? v : [v];
2319

2420
List<String> get urls => _urls;
2521
}

0 commit comments

Comments
 (0)