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

Commit

Permalink
perf(view factory): Compute DI Keys ahead of time
Browse files Browse the repository at this point in the history
4% improvement in TreeComponent benchmark

For #1081

Closes #1085
  • Loading branch information
jbdeboer authored and travis@travis-ci.org committed May 30, 2014
1 parent 61f3348 commit 317c23c
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 56 deletions.
3 changes: 2 additions & 1 deletion lib/core_dom/common.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ class MappingParts {
class DirectiveRef {
final dom.Node element;
final Type type;
final Key typeKey;
final Directive annotation;
final String value;
final mappings = new List<MappingParts>();

DirectiveRef(this.element, this.type, this.annotation, [ this.value ]);
DirectiveRef(this.element, this.type, this.annotation, this.typeKey, [ this.value ]);

String toString() {
var html = element is dom.Element
Expand Down
51 changes: 26 additions & 25 deletions lib/core_dom/element_binder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ class TemplateElementBinder extends ElementBinder {
_registerViewFactory(node, parentInjector, nodeModule) {
assert(templateViewFactory != null);
nodeModule
..bind(ViewPort, toFactory: (_) =>
new ViewPort(node, parentInjector.get(Animate)))
..bind(ViewFactory, toValue: templateViewFactory)
..bind(BoundViewFactory, toFactory: (Injector injector) =>
..bindByKey(_VIEW_PORT_KEY, toFactory: (_) =>
new ViewPort(node, parentInjector.getByKey(_ANIMATE_KEY)))
..bindByKey(_VIEW_FACTORY_KEY, toValue: templateViewFactory)
..bindByKey(_BOUND_VIEW_FACTORY_KEY, toFactory: (Injector injector) =>
templateViewFactory.bind(injector));
}
}
Expand Down Expand Up @@ -203,7 +203,7 @@ class ElementBinder {

void _link(nodeInjector, probe, scope, nodeAttrs, formatters) {
_usableDirectiveRefs.forEach((DirectiveRef ref) {
var directive = nodeInjector.get(ref.type);
var directive = nodeInjector.getByKey(ref.typeKey);
probe.directives.add(directive);

if (ref.annotation is Controller) {
Expand Down Expand Up @@ -240,18 +240,18 @@ class ElementBinder {
void _createDirectiveFactories(DirectiveRef ref, nodeModule, node, nodesAttrsDirectives, nodeAttrs,
visibility) {
if (ref.type == TextMustache) {
nodeModule.bind(TextMustache, toFactory: (Injector injector) {
return new TextMustache(node, ref.value, injector.get(Interpolate),
injector.get(Scope), injector.get(FormatterMap));
nodeModule.bindByKey(_TEXT_MUSTACHE_KEY, toFactory: (Injector injector) {
return new TextMustache(node, ref.value, injector.getByKey(_INTERPOLATE_KEY),
injector.getByKey(_SCOPE_KEY), injector.getByKey(_FORMATTER_MAP_KEY));
});
} else if (ref.type == AttrMustache) {
if (nodesAttrsDirectives.isEmpty) {
nodeModule.bind(AttrMustache, toFactory: (Injector injector) {
var scope = injector.get(Scope);
var interpolate = injector.get(Interpolate);
var scope = injector.getByKey(_SCOPE_KEY);
var interpolate = injector.getByKey(_INTERPOLATE_KEY);
for (var ref in nodesAttrsDirectives) {
new AttrMustache(nodeAttrs, ref.value, interpolate, scope,
injector.get(FormatterMap));
injector.getByKey(_FORMATTER_MAP_KEY));
}
});
}
Expand All @@ -266,23 +266,24 @@ class ElementBinder {
} else {
factory = _componentFactory;
}
nodeModule.bind(ref.type, toFactory: factory.call(node, ref), visibility: visibility);
nodeModule.bindByKey(ref.typeKey, toFactory: factory.call(node, ref), visibility: visibility);
} else {
nodeModule.bind(ref.type, visibility: visibility);
nodeModule.bindByKey(ref.typeKey, visibility: visibility);
}
}

// Overridden in TemplateElementBinder
void _registerViewFactory(node, parentInjector, nodeModule) {
nodeModule..bind(ViewPort, toValue: null)
..bind(ViewFactory, toValue: null)
..bind(BoundViewFactory, toValue: null);
nodeModule..bindByKey(_VIEW_PORT_KEY, toValue: null)
..bindByKey(_VIEW_FACTORY_KEY, toValue: null)
..bindByKey(_BOUND_VIEW_FACTORY_KEY, toValue: null);
}


Injector bind(View view, Injector parentInjector, dom.Node node) {
Injector nodeInjector;
Scope scope = parentInjector.get(Scope);
FormatterMap formatters = parentInjector.get(FormatterMap);
Scope scope = parentInjector.getByKey(_SCOPE_KEY);
FormatterMap formatters = parentInjector.getByKey(_FORMATTER_MAP_KEY);
var nodeAttrs = node is dom.Element ? new NodeAttrs(node) : null;
ElementProbe probe;

Expand All @@ -291,12 +292,12 @@ class ElementBinder {

var nodesAttrsDirectives = [];
var nodeModule = new Module()
..bind(NgElement)
..bind(View, toValue: view)
..bind(dom.Element, toValue: node)
..bind(dom.Node, toValue: node)
..bind(NodeAttrs, toValue: nodeAttrs)
..bind(ElementProbe, toFactory: (_) => probe);
..bindByKey(_NG_ELEMENT_KEY)
..bindByKey(_VIEW_KEY, toValue: view)
..bindByKey(_ELEMENT_KEY, toValue: node)
..bindByKey(_NODE_KEY, toValue: node)
..bindByKey(_NODE_ATTRS_KEY, toValue: nodeAttrs)
..bindByKey(_ELEMENT_PROBE_KEY, toFactory: (_) => probe);

directiveRefs.forEach((DirectiveRef ref) {
Directive annotation = ref.annotation;
Expand All @@ -317,7 +318,7 @@ class ElementBinder {

nodeInjector = parentInjector.createChild([nodeModule]);
probe = _expando[node] = new ElementProbe(
parentInjector.get(ElementProbe), node, nodeInjector, scope);
parentInjector.getByKey(_ELEMENT_PROBE_KEY), node, nodeInjector, scope);

_link(nodeInjector, probe, scope, nodeAttrs, formatters);

Expand Down
1 change: 1 addition & 0 deletions lib/core_dom/module_internal.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ part 'transcluding_component_factory.dart';
part 'tree_sanitizer.dart';
part 'walking_compiler.dart';
part 'ng_element.dart';
part 'static_keys.dart';

class CoreDomModule extends Module {
CoreDomModule() {
Expand Down
6 changes: 3 additions & 3 deletions lib/core_dom/selector.dart
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class DirectiveSelector {
// the value. Yes it is a bit of a hack.
_directives[selectorRegExp.annotation].forEach((type) {
builder.addDirective(new DirectiveRef(
node, type, selectorRegExp.annotation, '$attrName=$value'));
node, type, selectorRegExp.annotation, new Key(type), '$attrName=$value'));
});
}
}
Expand Down Expand Up @@ -131,7 +131,7 @@ class DirectiveSelector {
if (selectorRegExp.regexp.hasMatch(value)) {
_directives[selectorRegExp.annotation].forEach((type) {
builder.addDirective(new DirectiveRef(node, type,
selectorRegExp.annotation, value));
selectorRegExp.annotation, new Key(type), value));
});
}
}
Expand Down Expand Up @@ -204,7 +204,7 @@ class _SelectorPart {
_addRefs(ElementBinderBuilder builder, List<_Directive> directives, dom.Node node,
[String attrValue]) {
directives.forEach((directive) {
builder.addDirective(new DirectiveRef(node, directive.type, directive.annotation, attrValue));
builder.addDirective(new DirectiveRef(node, directive.type, directive.annotation, new Key(directive.type), attrValue));
});
}

Expand Down
50 changes: 26 additions & 24 deletions lib/core_dom/shadow_dom_component_factory.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,24 @@ class ShadowDomComponentFactory implements ComponentFactory {

final Map<_ComponentAssetKey, async.Future<dom.StyleElement>> _styleElementCache = {};



FactoryFn call(dom.Node node, DirectiveRef ref) {
return (Injector injector) {
var component = ref.annotation as Component;
Scope scope = injector.get(Scope);
ViewCache viewCache = injector.get(ViewCache);
Http http = injector.get(Http);
TemplateCache templateCache = injector.get(TemplateCache);
DirectiveMap directives = injector.get(DirectiveMap);
NgBaseCss baseCss = injector.get(NgBaseCss);
Scope scope = injector.getByKey(_SCOPE_KEY);
ViewCache viewCache = injector.getByKey(_VIEW_CACHE_KEY);
Http http = injector.getByKey(_HTTP_KEY);
TemplateCache templateCache = injector.getByKey(_TEMPLATE_CACHE_KEY);
DirectiveMap directives = injector.getByKey(_DIRECTIVE_MAP_KEY);
NgBaseCss baseCss = injector.getByKey(_NG_BASE_CSS_KEY);
// This is a bit of a hack since we are returning different type then we are.
var componentFactory = new _ComponentFactory(node,
ref.type,
ref.typeKey,
component,
injector.get(dom.NodeTreeSanitizer),
injector.get(WebPlatform),
injector.get(ComponentCssRewriter),
injector.getByKey(_NODE_TREE_SANITIZER_KEY),
injector.getByKey(_WEB_PLATFORM_KEY),
injector.getByKey(_COMPONENT_CSS_REWRITER_KEY),
_expando,
baseCss,
_styleElementCache);
Expand All @@ -70,7 +72,7 @@ class ShadowDomComponentFactory implements ComponentFactory {
class _ComponentFactory implements Function {

final dom.Element element;
final Type type;
final Key typeKey;
final Component component;
final dom.NodeTreeSanitizer treeSanitizer;
final Expando _expando;
Expand All @@ -85,7 +87,7 @@ class _ComponentFactory implements Function {
Injector shadowInjector;
var controller;

_ComponentFactory(this.element, this.type, this.component, this.treeSanitizer,
_ComponentFactory(this.element, this.typeKey, this.component, this.treeSanitizer,
this.platform, this.componentCssRewriter, this._expando,
this._baseCss, this._styleElementCache);

Expand Down Expand Up @@ -164,7 +166,7 @@ class _ComponentFactory implements Function {
}
return shadowDom;
}));
controller = createShadowInjector(injector, templateLoader).get(type);
controller = createShadowInjector(injector, templateLoader).getByKey(typeKey);
ComponentFactory._setupOnShadowDomAttach(controller, templateLoader, shadowScope);
return controller;
}
Expand All @@ -177,17 +179,17 @@ class _ComponentFactory implements Function {

Injector createShadowInjector(injector, TemplateLoader templateLoader) {
var probe;
var shadowModule = new Module()
..bind(type)
..bind(NgElement)
..bind(EventHandler, toImplementation: ShadowRootEventHandler)
..bind(Scope, toValue: shadowScope)
..bind(TemplateLoader, toValue: templateLoader)
..bind(dom.ShadowRoot, toValue: shadowDom)
..bind(ElementProbe, toFactory: (_) => probe);
shadowInjector = injector.createChild([shadowModule], name: SHADOW_DOM_INJECTOR_NAME);
var shadowModule = new Module()
..bindByKey(typeKey)
..bindByKey(_NG_ELEMENT_KEY)
..bindByKey(_EVENT_HANDLER_KEY, toImplementation: ShadowRootEventHandler)
..bindByKey(_SCOPE_KEY, toValue: shadowScope)
..bindByKey(_TEMPLATE_LOADER_KEY, toValue: templateLoader)
..bindByKey(_SHADOW_ROOT_KEY, toValue: shadowDom)
..bindByKey(_ELEMENT_PROBE, toFactory: (_) => probe);
shadowInjector = injector.createChild([shadowModule], name: SHADOW_DOM_INJECTOR_NAME);
probe = _expando[shadowDom] = new ElementProbe(
injector.get(ElementProbe), shadowDom, shadowInjector, shadowScope);
injector.getByKey(_ELEMENT_PROBE), shadowDom, shadowInjector, shadowScope);
return shadowInjector;
}
}
Expand Down Expand Up @@ -220,4 +222,4 @@ class ComponentCssRewriter {
String call(String css, { String selector, String cssUrl} ) {
return css;
}
}
}
30 changes: 30 additions & 0 deletions lib/core_dom/static_keys.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
part of angular.core.dom_internal;

// Keys used to call Injector.getByKey and Module.bindByKey

Key _ANIMATE_KEY = new Key(Animate);
Key _BOUND_VIEW_FACTORY_KEY = new Key(BoundViewFactory);
Key _COMPONENT_CSS_REWRITER_KEY = new Key(ComponentCssRewriter);
Key _DIRECTIVE_MAP_KEY = new Key(DirectiveMap);
Key _ELEMENT_KEY = new Key(dom.Element);
Key _ELEMENT_PROBE_KEY = new Key(ElementProbe);
Key _ELEMENT_PROBE = new Key(ElementProbe);
Key _EVENT_HANDLER_KEY = new Key(EventHandler);
Key _FORMATTER_MAP_KEY = new Key(FormatterMap);
Key _HTTP_KEY = new Key(Http);
Key _INTERPOLATE_KEY = new Key(Interpolate);
Key _NG_BASE_CSS_KEY = new Key(NgBaseCss);
Key _NG_ELEMENT_KEY = new Key(NgElement);
Key _NODE_ATTRS_KEY = new Key(NodeAttrs);
Key _NODE_KEY = new Key(dom.Node);
Key _NODE_TREE_SANITIZER_KEY = new Key(dom.NodeTreeSanitizer);
Key _SCOPE_KEY = new Key(Scope);
Key _SHADOW_ROOT_KEY = new Key(dom.ShadowRoot);
Key _TEMPLATE_CACHE_KEY = new Key(TemplateCache);
Key _TEMPLATE_LOADER_KEY = new Key(TemplateLoader);
Key _TEXT_MUSTACHE_KEY = new Key(TextMustache);
Key _VIEW_CACHE_KEY = new Key(ViewCache);
Key _VIEW_FACTORY_KEY = new Key(ViewFactory);
Key _VIEW_KEY = new Key(View);
Key _VIEW_PORT_KEY = new Key(ViewPort);
Key _WEB_PLATFORM_KEY = new Key(WebPlatform);
4 changes: 3 additions & 1 deletion lib/core_dom/tagging_view_factory.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ class TaggingViewFactory implements ViewFactory {

BoundViewFactory bind(Injector injector) => new BoundViewFactory(this, injector);

static Key _EVENT_HANDLER_KEY = new Key(EventHandler);

View call(Injector injector, [List<dom.Node> nodes /* TODO: document fragment */]) {
if (nodes == null) {
nodes = cloneElements(templateNodes);
}
var timerId;
try {
assert((timerId = _perf.startTimer('ng.view')) != false);
var view = new View(nodes, injector.get(EventHandler));
var view = new View(nodes, injector.getByKey(_EVENT_HANDLER_KEY));
_link(view, nodes, injector);
return view;
} finally {
Expand Down
4 changes: 3 additions & 1 deletion lib/core_dom/view_factory.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ class BoundViewFactory {

BoundViewFactory(this.viewFactory, this.injector);

static Key _SCOPE_KEY = new Key(Scope);

View call(Scope scope) =>
viewFactory(injector.createChild([new Module()..bind(Scope, toValue: scope)]));
viewFactory(injector.createChild([new Module()..bindByKey(_SCOPE_KEY, toValue: scope)]));
}

abstract class ViewFactory implements Function {
Expand Down
2 changes: 1 addition & 1 deletion test/core_dom/element_binder_builder_spec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ main() => describe('ElementBinderBuilder', () {
addDirective(selector) {
directives.forEach((Directive annotation, Type type) {
if (annotation.selector == selector)
b.addDirective(new DirectiveRef(node, type, annotation, null));
b.addDirective(new DirectiveRef(node, type, annotation, new Key(type), null));
});
b = b.binder;
}
Expand Down

0 comments on commit 317c23c

Please sign in to comment.