Skip to content

Commit 3e51644

Browse files
committed
perf(View): Improve View instantiation speed and memory consumption.
View contains many injectors which are expensive in both speed and memory. The New DirectiveInjector assumes that there are no more than 10 directives per element and can be a lot more efficient than a array/hash lookup and those it can be faster as well as smaller. This change makes View instantiation speed 4x faster in Dartium VM. BREAKING CHANGE: - Injector no longer supports visibility - The Directive:module instead of returning Module now takes DirectiveModule (which supports visibility) - Application Injector and DirectiveInjector now have separate trees. (The root if DirectiveInjector is ApplicationInjector)
1 parent e0c8d78 commit 3e51644

File tree

72 files changed

+1163
-533
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+1163
-533
lines changed

benchmark/pubspec.lock

+8-6
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ packages:
44
analyzer:
55
description: analyzer
66
source: hosted
7-
version: "0.13.6"
7+
version: "0.15.7"
88
angular:
99
description:
1010
path: ".."
@@ -30,23 +30,25 @@ packages:
3030
code_transformers:
3131
description: code_transformers
3232
source: hosted
33-
version: "0.1.3"
33+
version: "0.1.4+2"
3434
collection:
3535
description: collection
3636
source: hosted
3737
version: "0.9.2"
3838
di:
39-
description: di
40-
source: hosted
41-
version: "1.0.0"
39+
description:
40+
path: "../../di.dart"
41+
relative: true
42+
source: path
43+
version: "2.0.0-alpha.9"
4244
html5lib:
4345
description: html5lib
4446
source: hosted
4547
version: "0.10.0"
4648
intl:
4749
description: intl
4850
source: hosted
49-
version: "0.9.9"
51+
version: "0.9.10"
5052
logging:
5153
description: logging
5254
source: hosted

benchmark/pubspec.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ transformers:
1313
- $dart2js:
1414
minify: false
1515
checked: false
16+
commandLineOptions: [--dump-info]

benchmark/web/tree.dart

+1
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ class NgFreeTreeClass implements ShadowRootAware {
246246

247247
// Main function runs the benchmark.
248248
main() {
249+
setupModuleTypeReflector();
249250
var cleanup, createDom;
250251

251252
var module = new Module()

bin/parser_generator_for_spec.dart

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import 'dart:io' as io;
22

33
import 'package:di/di.dart';
4-
import 'package:di/dynamic_injector.dart';
54
import 'package:angular/cache/module.dart';
65
import 'package:angular/core/parser/lexer.dart';
76
import 'package:angular/core/parser/parser.dart';
@@ -14,8 +13,7 @@ main(arguments) {
1413
..bind(Parser, toImplementation: DynamicParser)
1514
..install(new CacheModule());
1615
module.bind(ParserBackend, toImplementation: DartGetterSetterGen);
17-
Injector injector = new DynamicInjector(modules: [module],
18-
allowImplicitInjection: true);
16+
Injector injector = new ModuleInjector([module]);
1917

2018
// List generated using:
2119
// node node_modules/karma/bin/karma run | grep -Eo ":XNAY:.*:XNAY:" | sed -e 's/:XNAY://g' | sed -e "s/^/'/" | sed -e "s/$/',/" | sort | uniq > missing_expressions

lib/application.dart

+8-5
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ import 'package:angular/routing/module.dart';
8484
import 'package:angular/introspection.dart';
8585

8686
import 'package:angular/core_dom/static_keys.dart';
87+
import 'package:angular/core_dom/directive_injector.dart';
8788

8889
/**
8990
* This is the top level module which describes all Angular components,
@@ -96,6 +97,7 @@ import 'package:angular/core_dom/static_keys.dart';
9697
*/
9798
class AngularModule extends Module {
9899
AngularModule() {
100+
DirectiveInjector.initUID();
99101
install(new CacheModule());
100102
install(new CoreModule());
101103
install(new CoreDomModule());
@@ -105,7 +107,6 @@ class AngularModule extends Module {
105107
install(new PerfModule());
106108
install(new RoutingModule());
107109

108-
bind(MetadataExtractor);
109110
bind(Expando, toValue: elementExpando);
110111
}
111112
}
@@ -175,9 +176,11 @@ abstract class Application {
175176
injector.getByKey(JS_CACHE_REGISTER_KEY);
176177
initializeDateFormatting(null, null).then((_) {
177178
try {
178-
var compiler = injector.getByKey(COMPILER_KEY);
179-
var viewFactory = compiler(rootElements, injector.getByKey(DIRECTIVE_MAP_KEY));
180-
viewFactory(injector, rootElements);
179+
Compiler compiler = injector.getByKey(COMPILER_KEY);
180+
DirectiveMap directiveMap = injector.getByKey(DIRECTIVE_MAP_KEY);
181+
RootScope rootScope = injector.getByKey(ROOT_SCOPE_KEY);
182+
ViewFactory viewFactory = compiler(rootElements, directiveMap);
183+
viewFactory(rootScope, injector.get(DirectiveInjector), rootElements);
181184
} catch (e, s) {
182185
exceptionHandler(e, s);
183186
}
@@ -190,5 +193,5 @@ abstract class Application {
190193
* Creates an injector function that can be used for retrieving services as well as for
191194
* dependency injection.
192195
*/
193-
Injector createInjector();
196+
Injector createInjector() => new ModuleInjector(modules);
194197
}

lib/application_factory.dart

-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
*/
1010
library angular.app.factory;
1111

12-
import 'package:di/dynamic_injector.dart';
1312
import 'package:angular/angular.dart';
1413
import 'package:angular/core/registry.dart';
1514
import 'package:angular/core/parser/parser.dart' show ClosureMap;
@@ -64,8 +63,6 @@ class _DynamicApplication extends Application {
6463
..bind(FieldGetterFactory, toImplementation: DynamicFieldGetterFactory)
6564
..bind(ClosureMap, toImplementation: DynamicClosureMap);
6665
}
67-
68-
Injector createInjector() => new DynamicInjector(modules: modules);
6966
}
7067

7168
/**

lib/application_factory_static.dart

+9-17
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@
3030
*/
3131
library angular.app.factory.static;
3232

33-
import 'package:di/static_injector.dart';
34-
import 'package:di/di.dart' show TypeFactory, Injector;
3533
import 'package:angular/application.dart';
3634
import 'package:angular/core/registry.dart';
3735
import 'package:angular/core/parser/parser.dart';
@@ -46,9 +44,7 @@ export 'package:angular/change_detection/change_detection.dart' show
4644
FieldSetter;
4745

4846
class _StaticApplication extends Application {
49-
final Map<Type, TypeFactory> typeFactories;
50-
51-
_StaticApplication(Map<Type, TypeFactory> this.typeFactories,
47+
_StaticApplication(
5248
Map<Type, Object> metadata,
5349
Map<String, FieldGetter> fieldGetters,
5450
Map<String, FieldSetter> fieldSetters,
@@ -58,9 +54,6 @@ class _StaticApplication extends Application {
5854
..bind(FieldGetterFactory, toValue: new StaticFieldGetterFactory(fieldGetters))
5955
..bind(ClosureMap, toValue: new StaticClosureMap(fieldGetters, fieldSetters, symbols));
6056
}
61-
62-
Injector createInjector() =>
63-
new StaticInjector(modules: modules, typeFactories: typeFactories);
6457
}
6558

6659
/**
@@ -81,20 +74,19 @@ class _StaticApplication extends Application {
8174
* becomes:
8275
*
8376
* main() {
84-
* staticApplication(generated_static_injector.factories,
85-
* generated_static_metadata.typeAnnotations,
86-
* generated_static_expressions.getters,
87-
* generated_static_expressions.setters,
88-
* generated_static_expressions.symbols)
89-
* .addModule(new Module()..bind(HelloWorldController))
90-
* .run();
77+
* staticApplication(
78+
* generated_static_metadata.typeAnnotations,
79+
* generated_static_expressions.getters,
80+
* generated_static_expressions.setters,
81+
* generated_static_expressions.symbols)
82+
* .addModule(new Module()..bind(HelloWorldController))
83+
* .run();
9184
*
9285
*/
9386
Application staticApplicationFactory(
94-
Map<Type, TypeFactory> typeFactories,
9587
Map<Type, Object> metadata,
9688
Map<String, FieldGetter> fieldGetters,
9789
Map<String, FieldSetter> fieldSetters,
9890
Map<String, Symbol> symbols) {
99-
return new _StaticApplication(typeFactories, metadata, fieldGetters, fieldSetters, symbols);
91+
return new _StaticApplication(metadata, fieldGetters, fieldSetters, symbols);
10092
}

lib/cache/module.dart

+3
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,7 @@ class CacheModule extends Module {
1313
CacheModule() {
1414
bind(CacheRegister);
1515
}
16+
CacheModule.withReflector(reflector): super.withReflector(reflector) {
17+
bind(CacheRegister);
18+
}
1619
}

lib/change_detection/ast_parser.dart

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ library angular.change_detection.ast_parser;
22

33
import 'dart:collection';
44

5+
import 'package:di/di.dart' show Injectable;
56
import 'package:angular/core/parser/syntax.dart' as syntax;
67
import 'package:angular/core/parser/parser.dart';
78
import 'package:angular/core/formatter.dart';

lib/core/annotation.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ export "package:angular/core/annotation_src.dart" show
1313
Formatter,
1414
DirectiveBinder,
1515
DirectiveBinderFn,
16-
Injectable,
1716

1817
Directive,
1918
Component,
2019
Controller,
2120
Decorator,
21+
Visibility,
2222

2323
DirectiveAnnotation,
2424
NgAttr,

lib/core/annotation_src.dart

+23-42
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,28 @@
11
library angular.core.annotation_src;
22

3-
import "package:di/di.dart" show Injector, Visibility;
3+
import "package:di/di.dart" show Injector, Visibility, Factory;
44

55
abstract class DirectiveBinder {
6-
bind(key, {Function toFactory, inject,
7-
Visibility visibility: Directive.CHILDREN_VISIBILITY});
6+
bind(key, {Function toFactory, inject, Visibility visibility: Visibility.CHILDREN});
87
}
98

109
typedef void DirectiveBinderFn(DirectiveBinder module);
1110

1211
RegExp _ATTR_NAME = new RegExp(r'\[([^\]]+)\]$');
1312

14-
const String SHADOW_DOM_INJECTOR_NAME = 'SHADOW_INJECTOR';
15-
16-
skipShadow(Injector injector)
17-
=> injector.name == SHADOW_DOM_INJECTOR_NAME ? injector.parent : injector;
18-
19-
localVisibility (Injector requesting, Injector defining)
20-
=> identical(skipShadow(requesting), defining);
21-
22-
directChildrenVisibility(Injector requesting, Injector defining) {
23-
requesting = skipShadow(requesting);
24-
return identical(requesting.parent, defining) || localVisibility(requesting, defining);
25-
}
26-
2713
Directive cloneWithNewMap(Directive annotation, map)
2814
=> annotation._cloneWithNewMap(map);
2915

3016
String mappingSpec(DirectiveAnnotation annotation) => annotation._mappingSpec;
3117

18+
class Visibility {
19+
static const LOCAL = const Visibility._('LOCAL');
20+
static const CHILDREN = const Visibility._('CHILDREN');
21+
static const DIRECT_CHILD = const Visibility._('DIRECT_CHILD');
3222

33-
/**
34-
* An annotation when applied to a class indicates that the class (service) will
35-
* be instantiated by di injector. This annotation is also used to designate which
36-
* classes need to have a static factory generated when using static angular, and
37-
* therefore is required on any injectable class.
38-
*/
39-
class Injectable {
40-
const Injectable();
23+
final String name;
24+
const Visibility._(this.name);
25+
toString() => 'Visibility: $name';
4126
}
4227

4328
/**
@@ -46,16 +31,19 @@ class Injectable {
4631
abstract class Directive {
4732

4833
/// The directive can only be injected to other directives on the same element.
49-
static const Visibility LOCAL_VISIBILITY = localVisibility;
34+
@deprecated // ('Use Visibility.LOCAL instead')
35+
static const Visibility LOCAL_VISIBILITY = Visibility.LOCAL;
5036

5137
/// The directive can be injected to other directives on the same or child elements.
52-
static const Visibility CHILDREN_VISIBILITY = null;
38+
@deprecated// ('Use Visibility.CHILDREN instead')
39+
static const Visibility CHILDREN_VISIBILITY = Visibility.CHILDREN;
5340

5441
/**
5542
* The directive on this element can only be injected to other directives
5643
* declared on elements which are direct children of the current element.
5744
*/
58-
static const Visibility DIRECT_CHILDREN_VISIBILITY = directChildrenVisibility;
45+
@deprecated// ('Use Visibility.DIRECT_CHILD instead')
46+
static const Visibility DIRECT_CHILDREN_VISIBILITY = Visibility.DIRECT_CHILD;
5947

6048
/**
6149
* CSS selector which will trigger this component/directive.
@@ -129,8 +117,8 @@ abstract class Directive {
129117
* selector: '[foo]',
130118
* module: Foo.moduleFactory)
131119
* class Foo {
132-
* static moduleFactory() => new Module()
133-
* ..bind(SomeTypeA, visibility: Directive.LOCAL_VISIBILITY);
120+
* static moduleFactory(DirectiveBinder binder) =>
121+
* binder.bind(SomeTypeA, visibility: Directive.LOCAL_VISIBILITY);
134122
* }
135123
*
136124
* When specifying types, factories or values in the module, notice that
@@ -139,7 +127,7 @@ abstract class Directive {
139127
* * [Directive.CHILDREN_VISIBILITY]
140128
* * [Directive.DIRECT_CHILDREN_VISIBILITY]
141129
*/
142-
final Function module;
130+
final DirectiveBinderFn module;
143131

144132
/**
145133
* Use map to define the mapping of DOM attributes to fields.
@@ -222,19 +210,15 @@ abstract class Directive {
222210

223211
const Directive({
224212
this.selector,
225-
this.children: Directive.COMPILE_CHILDREN,
226-
this.visibility: Directive.LOCAL_VISIBILITY,
213+
this.children,
214+
this.visibility,
227215
this.module,
228216
this.map: const {},
229217
this.exportExpressions: const [],
230218
this.exportExpressionAttrs: const []
231219
});
232220

233221
toString() => selector;
234-
get hashCode => selector.hashCode;
235-
operator==(other) =>
236-
other is Directive && selector == other.selector;
237-
238222
Directive _cloneWithNewMap(newMap);
239223
}
240224

@@ -335,7 +319,7 @@ class Component extends Directive {
335319
applyAuthorStyles,
336320
resetStyleInheritance,
337321
this.publishAs,
338-
module,
322+
DirectiveBinderFn module,
339323
map,
340324
selector,
341325
visibility,
@@ -393,7 +377,7 @@ class Decorator extends Directive {
393377
const Decorator({children: Directive.COMPILE_CHILDREN,
394378
map,
395379
selector,
396-
module,
380+
DirectiveBinderFn module,
397381
visibility,
398382
exportExpressions,
399383
exportExpressionAttrs})
@@ -446,7 +430,7 @@ class Controller extends Decorator {
446430
children: Directive.COMPILE_CHILDREN,
447431
this.publishAs,
448432
map,
449-
module,
433+
DirectiveBinderFn module,
450434
selector,
451435
visibility,
452436
exportExpressions,
@@ -595,8 +579,5 @@ class Formatter {
595579

596580
const Formatter({this.name});
597581

598-
int get hashCode => name.hashCode;
599-
bool operator==(other) => name == other.name;
600-
601582
toString() => 'Formatter: $name';
602583
}

lib/core/formatter.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class FormatterMap {
1414
final Injector _injector;
1515

1616
FormatterMap(this._injector, MetadataExtractor extractMetadata) {
17-
_injector.types.forEach((type) {
17+
(_injector as ModuleInjector).types.forEach((type) {
1818
extractMetadata(type)
1919
.where((annotation) => annotation is Formatter)
2020
.forEach((Formatter formatter) {

lib/core/module.dart

+3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ export "package:angular/cache/module.dart" show
2626
CacheRegister,
2727
CacheRegisterStats;
2828

29+
export "package:angular/core_dom/directive_injector.dart" show
30+
DirectiveInjector;
31+
2932
export "package:angular/core_dom/module_internal.dart" show
3033
Animation,
3134
AnimationResult,

0 commit comments

Comments
 (0)