benchmarks: add ng2_ftl and ng2_switch_ftl benchmarks (#11963)

These benchmarks take the output of AoT
and manually tweaks it to explore possible
future changes to the compiler to produce
this output directly.
This commit is contained in:
Tobias Bosch 2016-09-30 09:09:31 -07:00 committed by Chuck Jazdzewski
parent 42b4b6d21b
commit df1822fc2a
22 changed files with 1824 additions and 10 deletions

View File

@ -44,6 +44,20 @@ describe('tree benchmark perf', () => {
runTreeBenchmark({
id: `deepTree.ng2.${worker.id}`,
url: 'all/benchmarks/src/tree/ng2/index.html',
work: worker.work,
prepare: worker.prepare,
}).then(done, done.fail);
});
it('should run for ng2 ftl', (done) => {
runTreeBenchmark({
id: `deepTree.ng2.ftl.${worker.id}`,
url: 'all/benchmarks/src/tree/ng2_ftl/index.html',
work: worker.work,
prepare: worker.prepare,
// Can't use bundles as we use AoT generated code
// which relies on deep imports
extraParams: [{name: 'bundles', value: false}]
}).then(done, done.fail);
});
@ -51,6 +65,20 @@ describe('tree benchmark perf', () => {
runTreeBenchmark({
id: `deepTree.ng2.static.${worker.id}`,
url: 'all/benchmarks/src/tree/ng2_static/index.html',
work: worker.work,
prepare: worker.prepare,
}).then(done, done.fail);
});
it('should run for ng2 static ftl', (done) => {
runTreeBenchmark({
id: `deepTree.ng2.ftl.${worker.id}`,
url: 'all/benchmarks/src/tree/ng2_static_ftl/index.html',
work: worker.work,
prepare: worker.prepare,
// Can't use bundles as we use AoT generated code
// which relies on deep imports
extraParams: [{name: 'bundles', value: false}]
}).then(done, done.fail);
});
@ -58,6 +86,8 @@ describe('tree benchmark perf', () => {
runTreeBenchmark({
id: `deepTree.ng2_switch.${worker.id}`,
url: 'all/benchmarks/src/tree/ng2_switch/index.html',
work: worker.work,
prepare: worker.prepare,
}).then(done, done.fail);
});
@ -66,6 +96,8 @@ describe('tree benchmark perf', () => {
id: `deepTree.baseline.${worker.id}`,
url: 'all/benchmarks/src/tree/baseline/index.html',
ignoreBrowserSynchronization: true,
work: worker.work,
prepare: worker.prepare,
}).then(done, done.fail);
});
@ -74,6 +106,8 @@ describe('tree benchmark perf', () => {
id: `deepTree.incremental_dom.${worker.id}`,
url: 'all/benchmarks/src/tree/incremental_dom/index.html',
ignoreBrowserSynchronization: true,
work: worker.work,
prepare: worker.prepare,
}).then(done, done.fail);
});
@ -82,6 +116,8 @@ describe('tree benchmark perf', () => {
id: `deepTree.polymer.${worker.id}`,
url: 'all/benchmarks/src/tree/polymer/index.html',
ignoreBrowserSynchronization: true,
work: worker.work,
prepare: worker.prepare,
}).then(done, done.fail);
});
@ -90,22 +126,30 @@ describe('tree benchmark perf', () => {
id: `deepTree.polymer_leaves.${worker.id}`,
url: 'all/benchmarks/src/tree/polymer_leaves/index.html',
ignoreBrowserSynchronization: true,
work: worker.work,
prepare: worker.prepare,
}).then(done, done.fail);
});
});
});
function runTreeBenchmark(
config: {id: string, url: string, ignoreBrowserSynchronization?: boolean}) {
function runTreeBenchmark(config: {
id: string,
url: string, ignoreBrowserSynchronization?: boolean,
work: () => any,
prepare: () => any, extraParams?: {name: string, value: any}[]
}) {
let params = [{name: 'depth', value: 11}];
if (config.extraParams) {
params = params.concat(config.extraParams);
}
return runBenchmark({
id: config.id,
url: config.url,
ignoreBrowserSynchronization: config.ignoreBrowserSynchronization,
params: [{name: 'depth', value: 9}],
work: () => {
$('#createDom').click();
$('#destroyDom').click();
}
params: params,
work: config.work,
prepare: config.prepare
});
}
});

View File

@ -18,12 +18,30 @@ describe('tree benchmark spec', () => {
});
});
it('should work for ng2 ftl', () => {
testTreeBenchmark({
url: 'all/benchmarks/src/tree/ng2_ftl/index.html',
// Can't use bundles as we use AoT generated code
// which relies on deep imports
extraParams: [{name: 'bundles', value: false}]
});
});
it('should work for ng2 static', () => {
testTreeBenchmark({
url: 'all/benchmarks/src/tree/ng2_static/index.html',
});
});
it('should work for ng2 static ftl', () => {
testTreeBenchmark({
url: 'all/benchmarks/src/tree/ng2_static_ftl/index.html',
// Can't use bundles as we use AoT generated code
// which relies on deep imports
extraParams: [{name: 'bundles', value: false}]
});
});
it('should work for ng2 switch', () => {
testTreeBenchmark({
url: 'all/benchmarks/src/tree/ng2_switch/index.html',
@ -58,11 +76,19 @@ describe('tree benchmark spec', () => {
});
});
function testTreeBenchmark(openConfig: {url: string, ignoreBrowserSynchronization?: boolean}) {
function testTreeBenchmark(openConfig: {
url: string,
ignoreBrowserSynchronization?: boolean,
extraParams?: {name: string, value: any}[]
}) {
let params = [{name: 'depth', value: 4}];
if (openConfig.extraParams) {
params = params.concat(openConfig.extraParams);
}
openBrowser({
url: openConfig.url,
ignoreBrowserSynchronization: openConfig.ignoreBrowserSynchronization,
params: [{name: 'depth', value: 4}],
params: params,
});
$('#createDom').click();
expect($('#root').getText()).toContain('0');

View File

@ -0,0 +1,168 @@
# Ng2 Faster Than BaseLine (FTL) Benchmark
This benchmark was produced in a similar way as `ng2_static_ftl`,
but starting from the `ng2` benchmark, i.e. the benchmark
that only uses 1 component that contains itself via 2 `NgIf`s.
1. Run AoT over the `TreeComponent` and `AppModule`
2. Move the `ComponentFactory` and the corresponding host view class
from `tree.ngfactory.ts` into `tree_host.ngfactory.ts`
3. Move the `NgModuleFactory` into the `app.ngfactory.ts`
4. Optimize the `tree.ngfactory.ts` (see below)
The goal of this benchmark is to explore what kind of
code the Ng2 compiler should generate in order to get faster.
I.e. right now, the Ng2 compiler _does not_ produce this kind of code,
but hopefully will in the future.
## Optimizations and cleanups
See `tree.ngfactory.ts` and `tree_leaf.ngfactory.ts`.
Performance:
- remove view factory functions, call the constructor of the view class directly
- remove `createInternal` and move the logic into the constructor
- generate direct calls to `detectChangesInternal` / `destroyInternal` of nested components
_and_ view containers, don't use `viewChildren` / `contentChildren`
- remove `Renderer` and `SanitizationService` to update
the dom directly via `document.createElement` / `element.appendChild` / setting
`Text.nodeValue` / `Element.style....`
- remove `AppElement` on component host elements
- custom implementation of `ViewContainerRef` that uses
the views as linked list, instead of an array (see `ftl_util`).
- custom implementation of TemplateRef which not use a closure, only a view and an index,
and the view has a factory method that switches over the index
(see `ftl_util`).
- Don't wrap Views into ViewRefs before passing to the user.
- View does not use an array to store root nodes,
but rather has a generated method `visitRootNodes` (see below)
- ViewContainer, TemplateRef and views have minimal amount of fields
- use `insertBefore` as primitive.
Code size:
- inputs for `NgIf`, `TreeComponent` are wrapped into view class / directive wrapper method
(see `ng_if.ngfactory.ts` and `tree.ngfactory.ts`).
- helper methods `createElementAndAppend` / `createTextAndAppend` / `createAnchorAndAppend`
- remove `injectorGetInternal` assuming we can detect that nobody is injecting an `Injector`
## Properties
- no allocation of arrays nor closures
## Background: why `visitRootNodes`?
* An embedded view has root nodes that need to be attached / detached
to the DOM when the view is inserted.
* An embedded view can have view containers as root nodes. I.e. the root nodes
of a view need to include the root nodes of all views in root view containers
* An embedded view can have `<ng-content>` as root nodes. I.e. the root
nodes of a view need to include the projects nodes, which can
include a view container, in which case they need to include the root nodes
of all included views as well.
Previous implementation:
The generated view classes would store a (possible nested) array of root nodes
that can contain regular DOM nodes as well as ViewContainers.
The helper method `flattenNestedViewRootNodes` is used to convert this array
into a flat array of node.
However, this generates a new array and is probably hard to optimize for
a vm.
### Solution
Generate loop functions / methods.
I.e. a method like:
```
loopRootNodes(cb: (obj: any, ctx: any), ctx: any) {
cb(this.node0, ctx);
...
}
```
These methods can easily be nested, i.e. a view container
can just loop over its views and call this method,
forwarding the callback!
Same is true for projection!
==> Tried it, no impact on the benchmark!
### Discarded Solution 1)
Generate `attach` / `detach` method on EmbeddedView,
which will `insertBefore` the root nodes. Also
generate `project` and `unproject` methods in the caller
of a component to add / remove nodes.
Problems:
- generates a lot of code!
- projected nodes can only be inserted into the DOM via
`insertBefore`, but never via `appendChild` as
the generated method `project` does it,
and it can do only one of these two, but not both.
### Discarded Solution 2)
Generate a method `rootNodes` on every view that will
do produce a flattened array of nodes by generating the
right `concat` statements.
Problems:
- allocates arrays and `concat` calls that slows things down
(an experiment showed about about 2-5%).
## Experiments tried
- just the fact of having another base class in the prototype chain
is not a problem!
- Using a linked list over the views vs an array in ViewContainerRef
has no impact on performance, given that we use `Array.prototype.push`
for adding if possible (only tried with ngIf though...)
* Using `Array.prototype.splice` to add made benchmark 2% slower though!
- creating an array with root nodes does not make the benchmark much slower.
* Using `flattenNestedViewRootNodes` made it 5-10% slower!
* Note that this benchmark only includes `NgIf`, i.e. it only
inserts 1 entry into the array.
- creating an additional comment node for the view container,
so it is safe to do `insertBefore`
* this slows the benchmark down by 14% (added 2 comment nodes)!
==> the number of comment nodes is important!
## Open experiments:
- using ViewRef as a separate wrapper, compared to
using the view itself as ref.
- using AppElement with an injector, native node, ...,
compared to not having all of these fields
- using `insertAfter` instead of `insertBefore`?
## Initial resuls: size
File size for view class of the component + the 2 embedded view classes (without imports nor host view factory):
* before: 140 LOC
* after: 104 LOC
## Initial results: Deep Tree Benchmark
BENCHMARK deepTree....
Description:
- bundles: false
- depth: 11
- forceGc: false
- regressionSlopeMetric: scriptTime
- runId: f9ae32f0-8580-11e6-914d-9f4f8dbfb5e8
- sampleSize: 20
- userAgent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36
...createOnly | gcAmount | gcTime | majorGcTime | pureScriptTime | renderTime | scriptTime
--------------- | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------
ng2 | 5926.64+-11% | 17.46+-5% | 0.02+-44% | 96.74+-9% | 49.72+-5% | 114.19+-8%
ng2.ftl | 584.50+-435% | 0.43+-435% | 0.00+-435% | 33.98+-7% | 50.27+-5% | 33.98+-7%
baseline | 0.00 | 0.00 | 0.00 | 15.83+-7% | 45.75+-4% | 15.83+-7%
incremental_dom | 100.82+-302% | 1.64+-321% | 0.00+-304% | 53.43+-9% | 43.96+-4% | 55.07+-13%
...update gcAmount | gcTime | majorGcTime | pureScriptTime | renderTime | scriptTime
--------------- | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------
ng2 | 0.00 | 0.00+-435% | 0.00+-435% | 22.82+-9% | 29.52+-6% | 22.82+-9%
ng2.ftl | 219.72+-301% | 0.97+-300% | 0.00+-302% | 17.37+-10% | 29.27+-5% | 17.37+-10%
baseline | 530.73+-178% | 0.55+-281% | 0.35+-434% | 25.82+-8% | 31.67+-11% | 25.82+-8%
incremental_dom | 1057.56+-200% | 0.28+-201% | 0.00+-204% | 22.50+-9% | 28.03+-4% | 22.50+-9%
Ratios (create, pureScriptTime):
- 2.8x faster than current implementation
- 1.5x faster than incremental DOM
- 2.1x slower than baseline

View File

@ -0,0 +1,319 @@
/**
* This file is generated by the Angular 2 template compiler.
* Do not edit.
*/
/* tslint:disable */
import * as import2 from '@angular/common/src/common_module';
import * as import5 from '@angular/common/src/localization';
import * as import6 from '@angular/core/src/application_init';
import * as import3 from '@angular/core/src/application_module';
import * as import8 from '@angular/core/src/application_ref';
import * as import19 from '@angular/core/src/application_tokens';
import * as import31 from '@angular/core/src/change_detection/differs/iterable_differs';
import * as import32 from '@angular/core/src/change_detection/differs/keyvalue_differs';
import * as import24 from '@angular/core/src/console';
import * as import17 from '@angular/core/src/di/injector';
import * as import26 from '@angular/core/src/error_handler';
import * as import33 from '@angular/core/src/i18n/tokens';
import * as import25 from '@angular/core/src/i18n/tokens';
import * as import9 from '@angular/core/src/linker/compiler';
import * as import0 from '@angular/core/src/linker/ng_module_factory';
import * as import15 from '@angular/core/src/linker/view_utils';
import * as import29 from '@angular/core/src/render/api';
import * as import30 from '@angular/core/src/security';
import * as import7 from '@angular/core/src/testability/testability';
import * as import22 from '@angular/core/src/zone/ng_zone';
import * as import4 from '@angular/platform-browser/src/browser';
import * as import16 from '@angular/platform-browser/src/browser/title';
import * as import28 from '@angular/platform-browser/src/dom/animation_driver';
import * as import23 from '@angular/platform-browser/src/dom/debug/ng_probe';
import * as import13 from '@angular/platform-browser/src/dom/dom_renderer';
import * as import27 from '@angular/platform-browser/src/dom/dom_tokens';
import * as import20 from '@angular/platform-browser/src/dom/events/dom_events';
import * as import11 from '@angular/platform-browser/src/dom/events/event_manager';
import * as import10 from '@angular/platform-browser/src/dom/events/hammer_gestures';
import * as import21 from '@angular/platform-browser/src/dom/events/key_events';
import * as import12 from '@angular/platform-browser/src/dom/shared_styles_host';
import * as import14 from '@angular/platform-browser/src/security/dom_sanitization_service';
import * as import1 from './tree';
import * as import18 from './tree_host.ngfactory';
class AppModuleInjector extends import0.NgModuleInjector<import1.AppModule> {
_CommonModule_0: import2.CommonModule;
_ApplicationModule_1: import3.ApplicationModule;
_BrowserModule_2: import4.BrowserModule;
_AppModule_3: import1.AppModule;
__LOCALE_ID_4: any;
__NgLocalization_5: import5.NgLocaleLocalization;
_ErrorHandler_6: any;
_ApplicationInitStatus_7: import6.ApplicationInitStatus;
_Testability_8: import7.Testability;
_ApplicationRef__9: import8.ApplicationRef_;
__ApplicationRef_10: any;
__Compiler_11: import9.Compiler;
__APP_ID_12: any;
__DOCUMENT_13: any;
__HAMMER_GESTURE_CONFIG_14: import10.HammerGestureConfig;
__EVENT_MANAGER_PLUGINS_15: any[];
__EventManager_16: import11.EventManager;
__DomSharedStylesHost_17: import12.DomSharedStylesHost;
__AnimationDriver_18: any;
__DomRootRenderer_19: import13.DomRootRenderer_;
__RootRenderer_20: any;
__DomSanitizer_21: import14.DomSanitizerImpl;
__Sanitizer_22: any;
__ViewUtils_23: import15.ViewUtils;
__IterableDiffers_24: any;
__KeyValueDiffers_25: any;
__SharedStylesHost_26: any;
__Title_27: import16.Title;
__TRANSLATIONS_FORMAT_28: any;
constructor(parent: import17.Injector) {
super(parent, [import18.TreeComponentNgFactory], [import18.TreeComponentNgFactory]);
}
get _LOCALE_ID_4(): any {
if ((this.__LOCALE_ID_4 == (null as any))) {
(this.__LOCALE_ID_4 = (null as any));
}
return this.__LOCALE_ID_4;
}
get _NgLocalization_5(): import5.NgLocaleLocalization {
if ((this.__NgLocalization_5 == (null as any))) {
(this.__NgLocalization_5 = new import5.NgLocaleLocalization(this._LOCALE_ID_4));
}
return this.__NgLocalization_5;
}
get _ApplicationRef_10(): any {
if ((this.__ApplicationRef_10 == (null as any))) {
(this.__ApplicationRef_10 = this._ApplicationRef__9);
}
return this.__ApplicationRef_10;
}
get _Compiler_11(): import9.Compiler {
if ((this.__Compiler_11 == (null as any))) {
(this.__Compiler_11 = new import9.Compiler());
}
return this.__Compiler_11;
}
get _APP_ID_12(): any {
if ((this.__APP_ID_12 == (null as any))) {
(this.__APP_ID_12 = import19._appIdRandomProviderFactory());
}
return this.__APP_ID_12;
}
get _DOCUMENT_13(): any {
if ((this.__DOCUMENT_13 == (null as any))) {
(this.__DOCUMENT_13 = import4._document());
}
return this.__DOCUMENT_13;
}
get _HAMMER_GESTURE_CONFIG_14(): import10.HammerGestureConfig {
if ((this.__HAMMER_GESTURE_CONFIG_14 == (null as any))) {
(this.__HAMMER_GESTURE_CONFIG_14 = new import10.HammerGestureConfig());
}
return this.__HAMMER_GESTURE_CONFIG_14;
}
get _EVENT_MANAGER_PLUGINS_15(): any[] {
if ((this.__EVENT_MANAGER_PLUGINS_15 == (null as any))) {
(this.__EVENT_MANAGER_PLUGINS_15 = [
new import20.DomEventsPlugin(), new import21.KeyEventsPlugin(),
new import10.HammerGesturesPlugin(this._HAMMER_GESTURE_CONFIG_14)
]);
}
return this.__EVENT_MANAGER_PLUGINS_15;
}
get _EventManager_16(): import11.EventManager {
if ((this.__EventManager_16 == (null as any))) {
(this.__EventManager_16 = new import11.EventManager(
this._EVENT_MANAGER_PLUGINS_15, this.parent.get(import22.NgZone)));
}
return this.__EventManager_16;
}
get _DomSharedStylesHost_17(): import12.DomSharedStylesHost {
if ((this.__DomSharedStylesHost_17 == (null as any))) {
(this.__DomSharedStylesHost_17 = new import12.DomSharedStylesHost(this._DOCUMENT_13));
}
return this.__DomSharedStylesHost_17;
}
get _AnimationDriver_18(): any {
if ((this.__AnimationDriver_18 == (null as any))) {
(this.__AnimationDriver_18 = import4._resolveDefaultAnimationDriver());
}
return this.__AnimationDriver_18;
}
get _DomRootRenderer_19(): import13.DomRootRenderer_ {
if ((this.__DomRootRenderer_19 == (null as any))) {
(this.__DomRootRenderer_19 = new import13.DomRootRenderer_(
this._DOCUMENT_13, this._EventManager_16, this._DomSharedStylesHost_17,
this._AnimationDriver_18));
}
return this.__DomRootRenderer_19;
}
get _RootRenderer_20(): any {
if ((this.__RootRenderer_20 == (null as any))) {
(this.__RootRenderer_20 = import23._createConditionalRootRenderer(
this._DomRootRenderer_19, this.parent.get(import23.NgProbeToken, (null as any))));
}
return this.__RootRenderer_20;
}
get _DomSanitizer_21(): import14.DomSanitizerImpl {
if ((this.__DomSanitizer_21 == (null as any))) {
(this.__DomSanitizer_21 = new import14.DomSanitizerImpl());
}
return this.__DomSanitizer_21;
}
get _Sanitizer_22(): any {
if ((this.__Sanitizer_22 == (null as any))) {
(this.__Sanitizer_22 = this._DomSanitizer_21);
}
return this.__Sanitizer_22;
}
get _ViewUtils_23(): import15.ViewUtils {
if ((this.__ViewUtils_23 == (null as any))) {
(this.__ViewUtils_23 =
new import15.ViewUtils(this._RootRenderer_20, this._APP_ID_12, this._Sanitizer_22));
}
return this.__ViewUtils_23;
}
get _IterableDiffers_24(): any {
if ((this.__IterableDiffers_24 == (null as any))) {
(this.__IterableDiffers_24 = import3._iterableDiffersFactory());
}
return this.__IterableDiffers_24;
}
get _KeyValueDiffers_25(): any {
if ((this.__KeyValueDiffers_25 == (null as any))) {
(this.__KeyValueDiffers_25 = import3._keyValueDiffersFactory());
}
return this.__KeyValueDiffers_25;
}
get _SharedStylesHost_26(): any {
if ((this.__SharedStylesHost_26 == (null as any))) {
(this.__SharedStylesHost_26 = this._DomSharedStylesHost_17);
}
return this.__SharedStylesHost_26;
}
get _Title_27(): import16.Title {
if ((this.__Title_27 == (null as any))) {
(this.__Title_27 = new import16.Title());
}
return this.__Title_27;
}
get _TRANSLATIONS_FORMAT_28(): any {
if ((this.__TRANSLATIONS_FORMAT_28 == (null as any))) {
(this.__TRANSLATIONS_FORMAT_28 = (null as any));
}
return this.__TRANSLATIONS_FORMAT_28;
}
createInternal(): import1.AppModule {
this._CommonModule_0 = new import2.CommonModule();
this._ApplicationModule_1 = new import3.ApplicationModule();
this._BrowserModule_2 =
new import4.BrowserModule(this.parent.get(import4.BrowserModule, (null as any)));
this._AppModule_3 = new import1.AppModule();
this._ErrorHandler_6 = import4.errorHandler();
this._ApplicationInitStatus_7 =
new import6.ApplicationInitStatus(this.parent.get(import6.APP_INITIALIZER, (null as any)));
this._Testability_8 = new import7.Testability(this.parent.get(import22.NgZone));
this._ApplicationRef__9 = new import8.ApplicationRef_(
this.parent.get(import22.NgZone), this.parent.get(import24.Console), this,
this._ErrorHandler_6, this, this._ApplicationInitStatus_7,
this.parent.get(import7.TestabilityRegistry, (null as any)), this._Testability_8);
return this._AppModule_3;
}
getInternal(token: any, notFoundResult: any): any {
if ((token === import2.CommonModule)) {
return this._CommonModule_0;
}
if ((token === import3.ApplicationModule)) {
return this._ApplicationModule_1;
}
if ((token === import4.BrowserModule)) {
return this._BrowserModule_2;
}
if ((token === import1.AppModule)) {
return this._AppModule_3;
}
if ((token === import25.LOCALE_ID)) {
return this._LOCALE_ID_4;
}
if ((token === import5.NgLocalization)) {
return this._NgLocalization_5;
}
if ((token === import26.ErrorHandler)) {
return this._ErrorHandler_6;
}
if ((token === import6.ApplicationInitStatus)) {
return this._ApplicationInitStatus_7;
}
if ((token === import7.Testability)) {
return this._Testability_8;
}
if ((token === import8.ApplicationRef_)) {
return this._ApplicationRef__9;
}
if ((token === import8.ApplicationRef)) {
return this._ApplicationRef_10;
}
if ((token === import9.Compiler)) {
return this._Compiler_11;
}
if ((token === import19.APP_ID)) {
return this._APP_ID_12;
}
if ((token === import27.DOCUMENT)) {
return this._DOCUMENT_13;
}
if ((token === import10.HAMMER_GESTURE_CONFIG)) {
return this._HAMMER_GESTURE_CONFIG_14;
}
if ((token === import11.EVENT_MANAGER_PLUGINS)) {
return this._EVENT_MANAGER_PLUGINS_15;
}
if ((token === import11.EventManager)) {
return this._EventManager_16;
}
if ((token === import12.DomSharedStylesHost)) {
return this._DomSharedStylesHost_17;
}
if ((token === import28.AnimationDriver)) {
return this._AnimationDriver_18;
}
if ((token === import13.DomRootRenderer)) {
return this._DomRootRenderer_19;
}
if ((token === import29.RootRenderer)) {
return this._RootRenderer_20;
}
if ((token === import14.DomSanitizer)) {
return this._DomSanitizer_21;
}
if ((token === import30.Sanitizer)) {
return this._Sanitizer_22;
}
if ((token === import15.ViewUtils)) {
return this._ViewUtils_23;
}
if ((token === import31.IterableDiffers)) {
return this._IterableDiffers_24;
}
if ((token === import32.KeyValueDiffers)) {
return this._KeyValueDiffers_25;
}
if ((token === import12.SharedStylesHost)) {
return this._SharedStylesHost_26;
}
if ((token === import16.Title)) {
return this._Title_27;
}
if ((token === import33.TRANSLATIONS_FORMAT)) {
return this._TRANSLATIONS_FORMAT_28;
}
return notFoundResult;
}
destroyInternal(): void { this._ApplicationRef__9.ngOnDestroy(); }
}
export const AppModuleNgFactory: import0.NgModuleFactory<import1.AppModule> =
new import0.NgModuleFactory(AppModuleInjector, import1.AppModule);

View File

@ -0,0 +1,199 @@
import {ComponentFactory, ComponentRef, ElementRef, Injector, TemplateRef, ViewContainerRef, ViewRef} from '@angular/core';
export function unimplemented(): any {
throw new Error('unimplemented');
}
export interface FtlView<C> {
context: C;
detectChangesInternal(throwOnChange: boolean): void;
createEmbeddedView?<NC>(context: NC, nodeIndex: number): FtlEmbeddedView<NC>;
destroyInternal(): void;
}
export interface FtlEmbeddedView<C> extends FtlView<C> {
// Note: if the view has a view container as first node,
// create a comment node before it. This makes
// inserting a view before this view simpler!
_node0: any;
prev: FtlEmbeddedView<any>;
next: FtlEmbeddedView<any>;
// Purpose of the `ctx` argument:
// Allows to use top level functions, i.e. no need to create closures!
visitRootNodes<CTX>(callback: (node: any, ctx: CTX) => void, ctx: CTX): void;
}
// TODO(tbosch): FTL EmbeddedViewRefs should have no
// methods / properties at all. Because of this we can just use the FtlView for it as well!
// TODO(tbosch): We can't cast to EmbededViewRef as that also has the `rootNodes` filled
// -> would need to generate code for that as well.
// Rather: change API for FTL to allow to call View.attachBefore / View.detach
// -> faster and we don't need to flatten the root nodes!
export type FtlEmbeddedViewRef<C> = FtlView<C>;
export class FtlTemplateRef<C> implements TemplateRef<C> {
constructor(private _index: number, private _view: FtlView<any>) {}
get elementRef(): ElementRef { return unimplemented(); }
createEmbeddedView(context: C): any {
return this._view.createEmbeddedView(context, this._index);
}
}
export class FtlViewContainerRef implements ViewContainerRef {
private _firstView: FtlEmbeddedView<any> = null;
private _lastView: FtlEmbeddedView<any> = null;
private _length = 0;
constructor(private _anchor: any) {}
detectChangesInternal(throwOnChange: boolean) {
let view = this._firstView;
while (view) {
view.detectChangesInternal(throwOnChange);
view = view.next;
}
}
// TODO(tbosch): don't allow this API in FTL mode!
get element(): ElementRef { return <ElementRef>unimplemented(); }
// TODO(tbosch): don't allow this API in FTL mode!
get injector(): Injector { return <Injector>unimplemented(); }
// TODO(tbosch): don't allow this API in FTL mode!
get parentInjector(): Injector { return <Injector>unimplemented(); }
destroyInternal() {
let view = this._firstView;
while (view) {
view.destroyInternal();
view = view.next;
}
}
clear(): void {
let view = this._firstView;
while (view) {
detachView(view);
view.destroyInternal();
view = view.next;
}
this._firstView = null;
this._lastView = null;
this._length = 0;
}
get(index: number): any {
var result = this._firstView;
while (index > 0 && result) {
result = result.next;
index--;
}
return result;
}
get length(): number { return this._length; };
createEmbeddedView<C>(templateRef: TemplateRef<C>, context?: C, index?: number): any {
const view = templateRef.createEmbeddedView(context);
return this.insert(view, index);
}
createComponent<C>(
componentFactory: ComponentFactory<C>, index?: number, injector?: Injector,
projectableNodes?: any[][]): ComponentRef<C> {
// TODO(tbosch): implement this!
return unimplemented();
}
insert(viewRef: ViewRef, index?: number): any {
const view: FtlEmbeddedView<any> = <any>viewRef;
let insertBeforeNode: any;
if (this._length === 0) {
this._firstView = this._lastView = view;
insertBeforeNode = this._anchor;
view.prev = null;
view.next = null;
} else if (index >= this._length) {
view.prev = this._lastView;
view.next = null;
this._lastView.next = view;
this._lastView = view;
insertBeforeNode = this._anchor;
} else {
// TODO(tbosch): implement this!
unimplemented();
}
attachViewBefore(view, insertBeforeNode);
this._length++;
}
detach(index?: number): any {
let view: FtlEmbeddedView<any>;
if (this._length === 1) {
view = this._firstView;
this._firstView = this._lastView = null;
} else if (index >= this._length) {
view = this._lastView;
this._lastView = view.prev;
view.prev = null;
this._lastView.next = null;
} else {
// TODO(tbosch): implement this!
unimplemented();
}
this._length--;
detachView(view);
return view;
}
move(viewRef: ViewRef, currentIndex: number): ViewRef {
// TODO(tbosch): implement this!
return unimplemented();
}
indexOf(viewRef: ViewRef): number {
// TODO(tbosch): implement this!
return unimplemented();
}
remove(index?: number): void {
var view: FtlView<any> = <any>this.detach(index);
view.destroyInternal();
}
}
function attachViewBefore(view: FtlEmbeddedView<any>, node: any) {
const parent = node.parentNode;
view.visitRootNodes(insertBefore, {parent: parent, refNode: node});
}
function insertBefore(node: any, ctx: {parent: any, refNode: any}) {
ctx.parent.insertBefore(node, ctx.refNode);
}
function detachView(view: FtlEmbeddedView<any>) {
view.visitRootNodes(remove, null);
}
function remove(node: any, ctx: any) {
node.remove();
}
export function createElementAndAppend(parent: any, name: string) {
const el = document.createElement(name);
parent.appendChild(el);
return el;
}
export function createTextAndAppend(parent: any) {
const txt = document.createTextNode('');
parent.appendChild(txt);
return txt;
}
export function createAnchorAndAppend(parent: any) {
const txt = document.createComment('');
parent.appendChild(txt);
return txt;
}

View File

@ -0,0 +1,26 @@
<!doctype html>
<html>
<body>
<h2>Params</h2>
<form>
Depth:
<input type="number" name="depth" placeholder="depth" value="9">
<br>
<button>Apply</button>
</form>
<h2>Ng2 FTL Tree Benchmark</h2>
<p>
<button id="destroyDom">destroyDom</button>
<button id="createDom">createDom</button>
<button id="updateDomProfile">profile updateDom</button>
<button id="createDomProfile">profile createDom</button>
</p>
<div>
<tree id="root"></tree>
</div>
<script src="../../bootstrap_ng2.js"></script>
</body>
</html>

View File

@ -0,0 +1,41 @@
import {ApplicationRef, NgModule, enableProdMode} from '@angular/core';
import {platformBrowser} from '@angular/platform-browser';
import {bindAction, profile} from '../../util';
import {TreeNode, buildTree, emptyTree} from '../util';
import {AppModuleNgFactory} from './app.ngfactory';
import {TreeComponent} from './tree';
export function main() {
let tree: TreeComponent;
let appRef: ApplicationRef;
function destroyDom() {
tree.data = emptyTree;
appRef.tick();
}
function createDom() {
tree.data = buildTree();
appRef.tick();
}
function noop() {}
function init() {
enableProdMode();
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory).then((ref) => {
const injector = ref.injector;
appRef = injector.get(ApplicationRef);
tree = appRef.components[0].instance;
bindAction('#destroyDom', destroyDom);
bindAction('#createDom', createDom);
bindAction('#updateDomProfile', profile(createDom, noop, 'update'));
bindAction('#createDomProfile', profile(createDom, destroyDom, 'create'));
});
}
init();
}

View File

@ -0,0 +1,20 @@
import {NgIf} from '@angular/common';
import {TemplateRef, ViewContainerRef} from '@angular/core';
import * as import7 from '@angular/core/src/change_detection/change_detection';
import * as import4 from '@angular/core/src/linker/view_utils';
export class NgIfWrapper {
directive: NgIf;
_expr_0: any;
constructor(viewContainerRef: ViewContainerRef, templateRef: TemplateRef<any>) {
this.directive = new NgIf(viewContainerRef, templateRef);
this._expr_0 = import7.UNINITIALIZED;
}
updateNgIf(throwOnChange: boolean, currVal: any) {
if (import4.checkBinding(throwOnChange, this._expr_0, currVal)) {
this.directive.ngIf = currVal;
this._expr_0 = currVal;
}
}
}

View File

@ -0,0 +1,127 @@
/**
* This file is hand tweeked based on
* the out put of the Angular 2 template compiler
* and then hand tweeked to show possible future output.
*/
/* tslint:disable */
import * as import10 from '@angular/common/src/directives/ng_if';
import * as import7 from '@angular/core/src/change_detection/change_detection';
import * as import5 from '@angular/core/src/di/injector';
import * as import9 from '@angular/core/src/linker/component_factory';
import * as import2 from '@angular/core/src/linker/element';
import * as import11 from '@angular/core/src/linker/template_ref';
import * as import1 from '@angular/core/src/linker/view';
import * as import6 from '@angular/core/src/linker/view_type';
import * as import4 from '@angular/core/src/linker/view_utils';
import * as import8 from '@angular/core/src/metadata/view';
import * as import0 from '@angular/core/src/render/api';
import * as import12 from '@angular/core/src/security';
import {FtlEmbeddedView, FtlTemplateRef, FtlView, FtlViewContainerRef, createAnchorAndAppend, createElementAndAppend, createTextAndAppend} from './ftl_util';
import {NgIfWrapper} from './ng_if.ngfactory';
import * as import3 from './tree';
export class _View_TreeComponent0 implements FtlView<import3.TreeComponent> {
context: import3.TreeComponent;
_el_0: any;
_text_1: any;
_anchor_2: any;
_vc_2: FtlViewContainerRef;
_TemplateRef_2_5: any;
_NgIf_2_6: NgIfWrapper;
_anchor_3: any;
_vc_3: FtlViewContainerRef;
_TemplateRef_3_5: any;
_NgIf_3_6: NgIfWrapper;
_expr_0: any;
_expr_1: any;
_expr_2: any;
constructor(parentRenderNode: any) {
this.context = new import3.TreeComponent();
this._el_0 = createElementAndAppend(parentRenderNode, 'span');
this._text_1 = createTextAndAppend(this._el_0);
this._anchor_2 = createAnchorAndAppend(parentRenderNode);
this._TemplateRef_2_5 = new FtlTemplateRef(2, this);
this._vc_2 = new FtlViewContainerRef(this._anchor_2);
this._NgIf_2_6 = new NgIfWrapper(this._vc_2, this._TemplateRef_2_5);
this._anchor_3 = createAnchorAndAppend(parentRenderNode);
this._TemplateRef_3_5 = new FtlTemplateRef(3, this);
this._vc_3 = new FtlViewContainerRef(this._anchor_3);
this._NgIf_3_6 = new NgIfWrapper(this._vc_3, this._TemplateRef_3_5);
this._expr_0 = import7.UNINITIALIZED;
this._expr_1 = import7.UNINITIALIZED;
this._expr_2 = import7.UNINITIALIZED;
}
detectChangesInternal(throwOnChange: boolean): void {
this._NgIf_2_6.updateNgIf(throwOnChange, (this.context.data.right != (null as any)));
this._NgIf_3_6.updateNgIf(throwOnChange, (this.context.data.left != (null as any)));
this._vc_2.detectChangesInternal(throwOnChange);
this._vc_3.detectChangesInternal(throwOnChange);
const currVal_0: any = ((this.context.data.depth % 2) ? '' : 'grey');
if (import4.checkBinding(throwOnChange, this._expr_0, currVal_0)) {
this._el_0.style.backgroundColor = currVal_0;
this._expr_0 = currVal_0;
}
const currVal_1: any = import4.interpolate(1, ' ', this.context.data.value, ' ');
if (import4.checkBinding(throwOnChange, this._expr_1, currVal_1)) {
this._text_1.nodeValue = currVal_1;
this._expr_1 = currVal_1;
}
}
destroyInternal() {
this._vc_2.destroyInternal();
this._vc_3.destroyInternal();
}
updateData(throwOnChange: boolean, currVal: any) {
if (import4.checkBinding(throwOnChange, this._expr_2, currVal)) {
this.context.data = currVal;
this._expr_2 = currVal;
}
}
createEmbeddedView(context: any, nodeIndex: number): any {
switch (nodeIndex) {
case 2:
return new _View_TreeComponent1(this, context);
case 3:
return new _View_TreeComponent2(this, context);
default:
return null;
}
}
}
class _View_TreeComponent1 implements FtlEmbeddedView<any> {
_node0: any;
_TreeComponent_0_4: _View_TreeComponent0;
prev: FtlEmbeddedView<any>;
next: FtlEmbeddedView<any>;
constructor(private parent: _View_TreeComponent0, public context: any) {
this._node0 = document.createElement('tree');
this._TreeComponent_0_4 = new _View_TreeComponent0(this._node0);
}
detectChangesInternal(throwOnChange: boolean): void {
this._TreeComponent_0_4.updateData(throwOnChange, this.parent.context.data.right);
this._TreeComponent_0_4.detectChangesInternal(throwOnChange);
}
visitRootNodes(cb: (...args: any[]) => void, ctx: any) { cb(this._node0, ctx); }
destroyInternal() { this._TreeComponent_0_4.destroyInternal(); }
}
class _View_TreeComponent2 implements FtlEmbeddedView<any> {
_node0: any;
_TreeComponent_0_4: _View_TreeComponent0;
prev: FtlEmbeddedView<any>;
next: FtlEmbeddedView<any>;
constructor(private parent: _View_TreeComponent0, public context: any) {
this._node0 = document.createElement('tree');
this._TreeComponent_0_4 = new _View_TreeComponent0(this._node0);
}
detectChangesInternal(throwOnChange: boolean): void {
this._TreeComponent_0_4.updateData(throwOnChange, this.parent.context.data.left);
this._TreeComponent_0_4.detectChangesInternal(throwOnChange);
}
visitRootNodes(cb: (...args: any[]) => void, ctx: any) { cb(this._node0, ctx); }
destroyInternal() { this._TreeComponent_0_4.destroyInternal(); }
}

View File

@ -0,0 +1,5 @@
import {TreeNode, emptyTree} from '../util';
export class TreeComponent { data: TreeNode = emptyTree; }
export class AppModule {}

View File

@ -0,0 +1,65 @@
/**
* This file is generated by the Angular 2 template compiler.
* Do not edit.
*/
/* tslint:disable */
import * as import10 from '@angular/common/src/directives/ng_if';
import * as import7 from '@angular/core/src/change_detection/change_detection';
import * as import5 from '@angular/core/src/di/injector';
import * as import9 from '@angular/core/src/linker/component_factory';
import * as import2 from '@angular/core/src/linker/element';
import * as import11 from '@angular/core/src/linker/template_ref';
import * as import1 from '@angular/core/src/linker/view';
import * as import6 from '@angular/core/src/linker/view_type';
import * as import4 from '@angular/core/src/linker/view_utils';
import * as import8 from '@angular/core/src/metadata/view';
import * as import0 from '@angular/core/src/render/api';
import * as import12 from '@angular/core/src/security';
import * as import3 from './tree';
import {_View_TreeComponent0} from './tree.ngfactory';
var renderType_TreeComponent_Host: import0.RenderComponentType = (null as any);
class _View_TreeComponent_Host0 extends import1.AppView<any> {
_el_0: any;
_vc_0: import2.AppElement;
_TreeComponent_0_4: _View_TreeComponent0;
constructor(
viewUtils: import4.ViewUtils, parentInjector: import5.Injector,
declarationEl: import2.AppElement) {
super(
_View_TreeComponent_Host0, renderType_TreeComponent_Host, import6.ViewType.HOST, viewUtils,
parentInjector, declarationEl, import7.ChangeDetectorStatus.CheckAlways);
}
createInternal(rootSelector: string): import2.AppElement {
this._el_0 = this.selectOrCreateHostElement('tree', rootSelector, (null as any));
this._vc_0 = new import2.AppElement(0, (null as any), this, this._el_0);
this._TreeComponent_0_4 = new _View_TreeComponent0(this._el_0);
this._vc_0.initComponent(this._TreeComponent_0_4.context, [], <any>this._TreeComponent_0_4);
this.init([].concat([this._el_0]), [this._el_0], [], []);
return this._vc_0;
}
detectChangesInternal(throwOnChange: boolean): void {
this._TreeComponent_0_4.detectChangesInternal(throwOnChange);
}
destroyInternal(): void { this._TreeComponent_0_4.destroyInternal(); }
injectorGetInternal(token: any, requestNodeIndex: number, notFoundResult: any): any {
if (((token === import3.TreeComponent) && (0 === requestNodeIndex))) {
return this._TreeComponent_0_4;
}
return notFoundResult;
}
}
function viewFactory_TreeComponent_Host0(
viewUtils: import4.ViewUtils, parentInjector: import5.Injector,
declarationEl: import2.AppElement): import1.AppView<any> {
if ((renderType_TreeComponent_Host === (null as any))) {
(renderType_TreeComponent_Host =
viewUtils.createRenderComponentType('', 0, import8.ViewEncapsulation.None, [], {}));
}
return new _View_TreeComponent_Host0(viewUtils, parentInjector, declarationEl);
}
export const TreeComponentNgFactory: import9.ComponentFactory<import3.TreeComponent> =
new import9.ComponentFactory<import3.TreeComponent>(
'tree', viewFactory_TreeComponent_Host0, import3.TreeComponent);

View File

@ -0,0 +1,79 @@
# Ng2 Static Faster Than BaseLine (FTL) Benchmark
This benchmark was produced in the following way:
1. Run AoT over the root component, one branch component
and the leaf component of the ng2_static benchmark
2. Move all 3 component classes to `tree.ts`
3. Add a `depth` property to the view factory constructor of
the `TreeBranchComponent` and pass it down to nested view factory calls
to be able to use the same view factory for all
nesting levels. This is just to make the experiment simpler to not
need to change so much code.
4. Optimize the `tree_branch.ngfactory.ts` and `tree_leaf.ngfactory.ts`
(see below)
The goal of this benchmark is to explore what kind of
code the Ng2 compiler should generate in order to get faster.
I.e. right now, the Ng2 compiler _does not_ produce this kind of code,
but hopefully will in the future.
## Optimizations and cleanups
See `tree_branch.ngfactory.ts` and `tree_leaf.ngfactory.ts`.
Performance:
- remove view factory functions, call the constructor of the view class directly
- remove `createInternal` and move the logic into the constructor
- remove `AppView` parent class
- generate direct calls to `detectChangesInternal` / `destroyInternal` of nested components
- remove `Renderer` and `SanitizationService` to update
the dom directly via `document.createElement` / `element.appendChild` / setting
`Text.nodeValue` / `Element.style....`
- remove `AppElement`
- create component instance in view constructor
Code size:
- helper methods `createElementAndAppend` / `createTextAndAppend` / `createAnchorAndAppend`
- wrap dirty check for `TreeComponent.data` into the method `updateData`
in the view class
- remove `injectorGetInternal` assuming we can detect that nobody is injecting an `Injector`
## Initial results: File size
File size for view class of the component (without imports nor host view factory):
* before: 81 LOC
* after: 53 LOC
## Initial results: Deep Tree Benchmark
BENCHMARK deepTree....
Description:
- bundles: false
- depth: 11
- forceGc: false
- regressionSlopeMetric: scriptTime
- runId: f9ae32f0-8580-11e6-914d-9f4f8dbfb5e8
- sampleSize: 20
- userAgent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36
...createOnly | gcAmount | gcTime | majorGcTime | pureScriptTime | renderTime | scriptTime
--------------- | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------
ng2.static | 10068.17+-33% | 9.50+-43% | 0.01+-84% | 83.01+-18% | 57.81+-19% | 92.33+-16%
ng2.ftl | 493.36+-435% | 0.65+-435% | 0.00+-435% | 28.48+-16% | 53.97+-7% | 28.48+-16%
baseline | 53.81+-435% | 0.10+-435% | 0.00+-435% | 19.79+-20% | 52.08+-19% | 19.89+-20%
incremental_dom | 311.14+-254% | 2.43+-248% | 0.00+-207% | 68.30+-20% | 59.31+-19% | 70.73+-19%
.....update | gcAmount | gcTime | majorGcTime | pureScriptTime | renderTime | scriptTime
--------------- | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------
ng2.static | 0.00 | 0.00 | 0.00 | 24.65+-12% | 31.43+-22% | 24.65+-12%
ng2.ftl | 0.00 | 0.00+-435% | 0.00+-435% | 16.02+-13% | 29.15+-9% | 16.02+-13%
baseline | 509.97+-176% | 0.65+-269% | 0.40+-434% | 28.32+-16% | 35.80+-33% | 28.32+-16%
incremental_dom | 961.48+-246% | 0.52+-311% | 0.31+-435% | 28.94+-19% | 36.13+-21% | 28.94+-19%
Ratios (create, pureScriptTime)
- 2.9x faster than current implementation
- 2.3x faster than incremental dom
- 1.4x slower than baseline

View File

@ -0,0 +1,319 @@
/**
* This file is generated by the Angular 2 template compiler.
* Do not edit.
*/
/* tslint:disable */
import * as import2 from '@angular/common/src/common_module';
import * as import5 from '@angular/common/src/localization';
import * as import6 from '@angular/core/src/application_init';
import * as import3 from '@angular/core/src/application_module';
import * as import8 from '@angular/core/src/application_ref';
import * as import19 from '@angular/core/src/application_tokens';
import * as import31 from '@angular/core/src/change_detection/differs/iterable_differs';
import * as import32 from '@angular/core/src/change_detection/differs/keyvalue_differs';
import * as import24 from '@angular/core/src/console';
import * as import17 from '@angular/core/src/di/injector';
import * as import26 from '@angular/core/src/error_handler';
import * as import33 from '@angular/core/src/i18n/tokens';
import * as import25 from '@angular/core/src/i18n/tokens';
import * as import9 from '@angular/core/src/linker/compiler';
import * as import0 from '@angular/core/src/linker/ng_module_factory';
import * as import15 from '@angular/core/src/linker/view_utils';
import * as import29 from '@angular/core/src/render/api';
import * as import30 from '@angular/core/src/security';
import * as import7 from '@angular/core/src/testability/testability';
import * as import22 from '@angular/core/src/zone/ng_zone';
import * as import4 from '@angular/platform-browser/src/browser';
import * as import16 from '@angular/platform-browser/src/browser/title';
import * as import28 from '@angular/platform-browser/src/dom/animation_driver';
import * as import23 from '@angular/platform-browser/src/dom/debug/ng_probe';
import * as import13 from '@angular/platform-browser/src/dom/dom_renderer';
import * as import27 from '@angular/platform-browser/src/dom/dom_tokens';
import * as import20 from '@angular/platform-browser/src/dom/events/dom_events';
import * as import11 from '@angular/platform-browser/src/dom/events/event_manager';
import * as import10 from '@angular/platform-browser/src/dom/events/hammer_gestures';
import * as import21 from '@angular/platform-browser/src/dom/events/key_events';
import * as import12 from '@angular/platform-browser/src/dom/shared_styles_host';
import * as import14 from '@angular/platform-browser/src/security/dom_sanitization_service';
import * as import1 from './app';
import * as import18 from './tree_root.ngfactory';
class AppModuleInjector extends import0.NgModuleInjector<import1.AppModule> {
_CommonModule_0: import2.CommonModule;
_ApplicationModule_1: import3.ApplicationModule;
_BrowserModule_2: import4.BrowserModule;
_AppModule_3: import1.AppModule;
__LOCALE_ID_4: any;
__NgLocalization_5: import5.NgLocaleLocalization;
_ErrorHandler_6: any;
_ApplicationInitStatus_7: import6.ApplicationInitStatus;
_Testability_8: import7.Testability;
_ApplicationRef__9: import8.ApplicationRef_;
__ApplicationRef_10: any;
__Compiler_11: import9.Compiler;
__APP_ID_12: any;
__DOCUMENT_13: any;
__HAMMER_GESTURE_CONFIG_14: import10.HammerGestureConfig;
__EVENT_MANAGER_PLUGINS_15: any[];
__EventManager_16: import11.EventManager;
__DomSharedStylesHost_17: import12.DomSharedStylesHost;
__AnimationDriver_18: any;
__DomRootRenderer_19: import13.DomRootRenderer_;
__RootRenderer_20: any;
__DomSanitizer_21: import14.DomSanitizerImpl;
__Sanitizer_22: any;
__ViewUtils_23: import15.ViewUtils;
__IterableDiffers_24: any;
__KeyValueDiffers_25: any;
__SharedStylesHost_26: any;
__Title_27: import16.Title;
__TRANSLATIONS_FORMAT_28: any;
constructor(parent: import17.Injector) {
super(parent, [import18.TreeRootComponentNgFactory], [import18.TreeRootComponentNgFactory]);
}
get _LOCALE_ID_4(): any {
if ((this.__LOCALE_ID_4 == (null as any))) {
(this.__LOCALE_ID_4 = (null as any));
}
return this.__LOCALE_ID_4;
}
get _NgLocalization_5(): import5.NgLocaleLocalization {
if ((this.__NgLocalization_5 == (null as any))) {
(this.__NgLocalization_5 = new import5.NgLocaleLocalization(this._LOCALE_ID_4));
}
return this.__NgLocalization_5;
}
get _ApplicationRef_10(): any {
if ((this.__ApplicationRef_10 == (null as any))) {
(this.__ApplicationRef_10 = this._ApplicationRef__9);
}
return this.__ApplicationRef_10;
}
get _Compiler_11(): import9.Compiler {
if ((this.__Compiler_11 == (null as any))) {
(this.__Compiler_11 = new import9.Compiler());
}
return this.__Compiler_11;
}
get _APP_ID_12(): any {
if ((this.__APP_ID_12 == (null as any))) {
(this.__APP_ID_12 = import19._appIdRandomProviderFactory());
}
return this.__APP_ID_12;
}
get _DOCUMENT_13(): any {
if ((this.__DOCUMENT_13 == (null as any))) {
(this.__DOCUMENT_13 = import4._document());
}
return this.__DOCUMENT_13;
}
get _HAMMER_GESTURE_CONFIG_14(): import10.HammerGestureConfig {
if ((this.__HAMMER_GESTURE_CONFIG_14 == (null as any))) {
(this.__HAMMER_GESTURE_CONFIG_14 = new import10.HammerGestureConfig());
}
return this.__HAMMER_GESTURE_CONFIG_14;
}
get _EVENT_MANAGER_PLUGINS_15(): any[] {
if ((this.__EVENT_MANAGER_PLUGINS_15 == (null as any))) {
(this.__EVENT_MANAGER_PLUGINS_15 = [
new import20.DomEventsPlugin(), new import21.KeyEventsPlugin(),
new import10.HammerGesturesPlugin(this._HAMMER_GESTURE_CONFIG_14)
]);
}
return this.__EVENT_MANAGER_PLUGINS_15;
}
get _EventManager_16(): import11.EventManager {
if ((this.__EventManager_16 == (null as any))) {
(this.__EventManager_16 = new import11.EventManager(
this._EVENT_MANAGER_PLUGINS_15, this.parent.get(import22.NgZone)));
}
return this.__EventManager_16;
}
get _DomSharedStylesHost_17(): import12.DomSharedStylesHost {
if ((this.__DomSharedStylesHost_17 == (null as any))) {
(this.__DomSharedStylesHost_17 = new import12.DomSharedStylesHost(this._DOCUMENT_13));
}
return this.__DomSharedStylesHost_17;
}
get _AnimationDriver_18(): any {
if ((this.__AnimationDriver_18 == (null as any))) {
(this.__AnimationDriver_18 = import4._resolveDefaultAnimationDriver());
}
return this.__AnimationDriver_18;
}
get _DomRootRenderer_19(): import13.DomRootRenderer_ {
if ((this.__DomRootRenderer_19 == (null as any))) {
(this.__DomRootRenderer_19 = new import13.DomRootRenderer_(
this._DOCUMENT_13, this._EventManager_16, this._DomSharedStylesHost_17,
this._AnimationDriver_18));
}
return this.__DomRootRenderer_19;
}
get _RootRenderer_20(): any {
if ((this.__RootRenderer_20 == (null as any))) {
(this.__RootRenderer_20 = import23._createConditionalRootRenderer(
this._DomRootRenderer_19, this.parent.get(import23.NgProbeToken, (null as any))));
}
return this.__RootRenderer_20;
}
get _DomSanitizer_21(): import14.DomSanitizerImpl {
if ((this.__DomSanitizer_21 == (null as any))) {
(this.__DomSanitizer_21 = new import14.DomSanitizerImpl());
}
return this.__DomSanitizer_21;
}
get _Sanitizer_22(): any {
if ((this.__Sanitizer_22 == (null as any))) {
(this.__Sanitizer_22 = this._DomSanitizer_21);
}
return this.__Sanitizer_22;
}
get _ViewUtils_23(): import15.ViewUtils {
if ((this.__ViewUtils_23 == (null as any))) {
(this.__ViewUtils_23 =
new import15.ViewUtils(this._RootRenderer_20, this._APP_ID_12, this._Sanitizer_22));
}
return this.__ViewUtils_23;
}
get _IterableDiffers_24(): any {
if ((this.__IterableDiffers_24 == (null as any))) {
(this.__IterableDiffers_24 = import3._iterableDiffersFactory());
}
return this.__IterableDiffers_24;
}
get _KeyValueDiffers_25(): any {
if ((this.__KeyValueDiffers_25 == (null as any))) {
(this.__KeyValueDiffers_25 = import3._keyValueDiffersFactory());
}
return this.__KeyValueDiffers_25;
}
get _SharedStylesHost_26(): any {
if ((this.__SharedStylesHost_26 == (null as any))) {
(this.__SharedStylesHost_26 = this._DomSharedStylesHost_17);
}
return this.__SharedStylesHost_26;
}
get _Title_27(): import16.Title {
if ((this.__Title_27 == (null as any))) {
(this.__Title_27 = new import16.Title());
}
return this.__Title_27;
}
get _TRANSLATIONS_FORMAT_28(): any {
if ((this.__TRANSLATIONS_FORMAT_28 == (null as any))) {
(this.__TRANSLATIONS_FORMAT_28 = (null as any));
}
return this.__TRANSLATIONS_FORMAT_28;
}
createInternal(): import1.AppModule {
this._CommonModule_0 = new import2.CommonModule();
this._ApplicationModule_1 = new import3.ApplicationModule();
this._BrowserModule_2 =
new import4.BrowserModule(this.parent.get(import4.BrowserModule, (null as any)));
this._AppModule_3 = new import1.AppModule();
this._ErrorHandler_6 = import4.errorHandler();
this._ApplicationInitStatus_7 =
new import6.ApplicationInitStatus(this.parent.get(import6.APP_INITIALIZER, (null as any)));
this._Testability_8 = new import7.Testability(this.parent.get(import22.NgZone));
this._ApplicationRef__9 = new import8.ApplicationRef_(
this.parent.get(import22.NgZone), this.parent.get(import24.Console), this,
this._ErrorHandler_6, this, this._ApplicationInitStatus_7,
this.parent.get(import7.TestabilityRegistry, (null as any)), this._Testability_8);
return this._AppModule_3;
}
getInternal(token: any, notFoundResult: any): any {
if ((token === import2.CommonModule)) {
return this._CommonModule_0;
}
if ((token === import3.ApplicationModule)) {
return this._ApplicationModule_1;
}
if ((token === import4.BrowserModule)) {
return this._BrowserModule_2;
}
if ((token === import1.AppModule)) {
return this._AppModule_3;
}
if ((token === import25.LOCALE_ID)) {
return this._LOCALE_ID_4;
}
if ((token === import5.NgLocalization)) {
return this._NgLocalization_5;
}
if ((token === import26.ErrorHandler)) {
return this._ErrorHandler_6;
}
if ((token === import6.ApplicationInitStatus)) {
return this._ApplicationInitStatus_7;
}
if ((token === import7.Testability)) {
return this._Testability_8;
}
if ((token === import8.ApplicationRef_)) {
return this._ApplicationRef__9;
}
if ((token === import8.ApplicationRef)) {
return this._ApplicationRef_10;
}
if ((token === import9.Compiler)) {
return this._Compiler_11;
}
if ((token === import19.APP_ID)) {
return this._APP_ID_12;
}
if ((token === import27.DOCUMENT)) {
return this._DOCUMENT_13;
}
if ((token === import10.HAMMER_GESTURE_CONFIG)) {
return this._HAMMER_GESTURE_CONFIG_14;
}
if ((token === import11.EVENT_MANAGER_PLUGINS)) {
return this._EVENT_MANAGER_PLUGINS_15;
}
if ((token === import11.EventManager)) {
return this._EventManager_16;
}
if ((token === import12.DomSharedStylesHost)) {
return this._DomSharedStylesHost_17;
}
if ((token === import28.AnimationDriver)) {
return this._AnimationDriver_18;
}
if ((token === import13.DomRootRenderer)) {
return this._DomRootRenderer_19;
}
if ((token === import29.RootRenderer)) {
return this._RootRenderer_20;
}
if ((token === import14.DomSanitizer)) {
return this._DomSanitizer_21;
}
if ((token === import30.Sanitizer)) {
return this._Sanitizer_22;
}
if ((token === import15.ViewUtils)) {
return this._ViewUtils_23;
}
if ((token === import31.IterableDiffers)) {
return this._IterableDiffers_24;
}
if ((token === import32.KeyValueDiffers)) {
return this._KeyValueDiffers_25;
}
if ((token === import12.SharedStylesHost)) {
return this._SharedStylesHost_26;
}
if ((token === import16.Title)) {
return this._Title_27;
}
if ((token === import33.TRANSLATIONS_FORMAT)) {
return this._TRANSLATIONS_FORMAT_28;
}
return notFoundResult;
}
destroyInternal(): void { this._ApplicationRef__9.ngOnDestroy(); }
}
export const AppModuleNgFactory: import0.NgModuleFactory<import1.AppModule> =
new import0.NgModuleFactory(AppModuleInjector, import1.AppModule);

View File

@ -0,0 +1 @@
export class AppModule {}

View File

@ -0,0 +1,17 @@
export function createElementAndAppend(parent: any, name: string) {
const el = document.createElement(name);
parent.appendChild(el);
return el;
}
export function createTextAndAppend(parent: any) {
const txt = document.createTextNode('');
parent.appendChild(txt);
return txt;
}
export function createAnchorAndAppend(parent: any) {
const txt = document.createComment('');
parent.appendChild(txt);
return txt;
}

View File

@ -0,0 +1,26 @@
<!doctype html>
<html>
<body>
<h2>Params</h2>
<form>
Depth:
<input type="number" name="depth" placeholder="depth" value="9">
<br>
<button>Apply</button>
</form>
<h2>Ng2 Static FTL Tree Benchmark</h2>
<p>
<button id="destroyDom">destroyDom</button>
<button id="createDom">createDom</button>
<button id="updateDomProfile">profile updateDom</button>
<button id="createDomProfile">profile createDom</button>
</p>
<div>
<tree id="root"></tree>
</div>
<script src="../../bootstrap_ng2.js"></script>
</body>
</html>

View File

@ -0,0 +1,41 @@
import {ApplicationRef, NgModule, enableProdMode} from '@angular/core';
import {platformBrowser} from '@angular/platform-browser';
import {bindAction, profile} from '../../util';
import {TreeNode, buildTree, emptyTree} from '../util';
import {AppModuleNgFactory} from './app.ngfactory';
import {TreeRootComponent} from './tree';
export function main() {
let tree: TreeRootComponent;
let appRef: ApplicationRef;
function destroyDom() {
tree.data = emptyTree;
appRef.tick();
}
function createDom() {
tree.data = buildTree();
appRef.tick();
}
function noop() {}
function init() {
enableProdMode();
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory).then((ref) => {
const injector = ref.injector;
appRef = injector.get(ApplicationRef);
tree = appRef.components[0].instance;
bindAction('#destroyDom', destroyDom);
bindAction('#createDom', createDom);
bindAction('#updateDomProfile', profile(createDom, noop, 'update'));
bindAction('#createDomProfile', profile(createDom, destroyDom, 'create'));
});
}
init();
}

View File

@ -0,0 +1,7 @@
import {TreeNode, emptyTree} from '../util';
export class TreeRootComponent { data: TreeNode = emptyTree; }
export class TreeBranchComponent { data: TreeNode; }
export class TreeLeafComponent { data: TreeNode; }

View File

@ -0,0 +1,76 @@
/**
* This file is hand tweeked based on
* the out put of the Angular 2 template compiler
* and then hand tweeked to show possible future output.
*/
/* tslint:disable */
import * as import7 from '@angular/core/src/change_detection/change_detection';
import * as import5 from '@angular/core/src/di/injector';
import * as import9 from '@angular/core/src/linker/component_factory';
import * as import2 from '@angular/core/src/linker/element';
import * as import1 from '@angular/core/src/linker/view';
import * as import6 from '@angular/core/src/linker/view_type';
import * as import4 from '@angular/core/src/linker/view_utils';
import * as import8 from '@angular/core/src/metadata/view';
import * as import0 from '@angular/core/src/render/api';
import * as import12 from '@angular/core/src/security';
import {createAnchorAndAppend, createElementAndAppend, createTextAndAppend} from './ftl_util';
import * as import3 from './tree';
import * as import11 from './tree_leaf.ngfactory';
export class View_TreeTreeComponent {
context: import3.TreeBranchComponent;
ref: any;
_el_0: any;
_text_1: any;
_el_2: any;
_TreeComponent20_2_4View: any;
_el_3: any;
_TreeComponent20_3_4View: any;
/*private*/ _expr_0: any;
/*private*/ _expr_1: any;
/*private*/ _expr_2: any;
constructor(depth: number, parentRenderNode: any) {
this.context = new import3.TreeBranchComponent();
this._el_0 = createElementAndAppend(parentRenderNode, 'span');
this._text_1 = createTextAndAppend(this._el_0);
this._el_2 = createElementAndAppend(parentRenderNode, 'tree');
this._TreeComponent20_2_4View = depth > 0 ? new View_TreeTreeComponent(depth - 1, this._el_2) :
new import11.View_TreeLeafComponent(this._el_2);
this._el_3 = createElementAndAppend(parentRenderNode, 'tree');
this._TreeComponent20_3_4View = depth > 0 ? new View_TreeTreeComponent(depth - 1, this._el_3) :
new import11.View_TreeLeafComponent(this._el_3);
this._expr_0 = import7.UNINITIALIZED;
this._expr_1 = import7.UNINITIALIZED;
this._expr_2 = import7.UNINITIALIZED;
}
destroyInternal() {
this._TreeComponent20_2_4View.destroyInternal();
this._TreeComponent20_3_4View.destroyInternal();
}
updateData(currVal_2: any) {
if (import4.checkBinding(false, this._expr_2, currVal_2)) {
this.context.data = currVal_2;
this._expr_2 = currVal_2;
}
}
detectChangesInternal(throwOnChange: boolean): void {
this._TreeComponent20_2_4View.updateData(this.context.data.right);
this._TreeComponent20_3_4View.updateData(this.context.data.left);
const currVal_0: any = ((this.context.data.depth % 2) ? '' : 'grey');
if (import4.checkBinding(throwOnChange, this._expr_0, currVal_0)) {
this._el_0.style.backgroundColor = currVal_0;
this._expr_0 = currVal_0;
}
const currVal_1: any = import4.interpolate(1, ' ', this.context.data.value, ' ');
if (import4.checkBinding(throwOnChange, this._expr_1, currVal_1)) {
this._text_1.nodeValue = currVal_1;
this._expr_1 = currVal_1;
}
this._TreeComponent20_2_4View.detectChangesInternal(throwOnChange);
this._TreeComponent20_3_4View.detectChangesInternal(throwOnChange);
}
}

View File

@ -0,0 +1,56 @@
/**
* This file is hand tweeked based on
* the out put of the Angular 2 template compiler
* and then hand tweeked to show possible future output.
*/
/* tslint:disable */
import * as import7 from '@angular/core/src/change_detection/change_detection';
import * as import5 from '@angular/core/src/di/injector';
import * as import9 from '@angular/core/src/linker/component_factory';
import * as import2 from '@angular/core/src/linker/element';
import * as import1 from '@angular/core/src/linker/view';
import * as import6 from '@angular/core/src/linker/view_type';
import * as import4 from '@angular/core/src/linker/view_utils';
import * as import8 from '@angular/core/src/metadata/view';
import * as import0 from '@angular/core/src/render/api';
import * as import10 from '@angular/core/src/security';
import * as import3 from './tree';
export class View_TreeLeafComponent {
context: import3.TreeLeafComponent;
_el_0: any;
_text_1: any;
/*private*/ _expr_0: any;
/*private*/ _expr_1: any;
/*private*/ _expr_2: any;
constructor(parentRenderNode: any) {
this.context = new import3.TreeLeafComponent();
this._el_0 = document.createElement('span');
parentRenderNode.appendChild(this._el_0);
this._text_1 = document.createTextNode('');
this._el_0.appendChild(this._text_1);
this._expr_0 = import7.UNINITIALIZED;
this._expr_1 = import7.UNINITIALIZED;
}
updateData(currVal_2: any) {
if (import4.checkBinding(false, this._expr_2, currVal_2)) {
this.context.data = currVal_2;
this._expr_2 = currVal_2;
}
}
destroyInternal() {}
detectChangesInternal(throwOnChange: boolean): void {
const currVal_0: any = ((this.context.data.depth % 2) ? '' : 'grey');
if (import4.checkBinding(throwOnChange, this._expr_0, currVal_0)) {
this._el_0.style.backgroundColor = currVal_0;
this._expr_0 = currVal_0;
}
const currVal_1: any = import4.interpolate(1, ' ', this.context.data.value, ' ');
if (import4.checkBinding(throwOnChange, this._expr_1, currVal_1)) {
this._text_1.nodeValue = currVal_1;
this._expr_1 = currVal_1;
}
}
}

View File

@ -0,0 +1,150 @@
/**
* This file is generated by the Angular 2 template compiler.
* Do not edit.
*/
/* tslint:disable */
import * as import10 from '@angular/common/src/directives/ng_if';
import * as import7 from '@angular/core/src/change_detection/change_detection';
import * as import5 from '@angular/core/src/di/injector';
import * as import9 from '@angular/core/src/linker/component_factory';
import * as import2 from '@angular/core/src/linker/element';
import * as import11 from '@angular/core/src/linker/template_ref';
import * as import1 from '@angular/core/src/linker/view';
import * as import6 from '@angular/core/src/linker/view_type';
import * as import4 from '@angular/core/src/linker/view_utils';
import * as import8 from '@angular/core/src/metadata/view';
import * as import0 from '@angular/core/src/render/api';
import {maxDepth} from '../util';
import * as import3 from './tree';
import * as import12 from './tree';
import * as import13 from './tree_branch.ngfactory';
var renderType_TreeRootComponent_Host: import0.RenderComponentType = (null as any);
class _View_TreeRootComponent_Host0 extends import1.AppView<any> {
_el_0: any;
/*private*/ _appEl_0: import2.AppElement;
_TreeRootComponent_0_4: import3.TreeRootComponent;
constructor(
viewUtils: import4.ViewUtils, parentInjector: import5.Injector,
declarationEl: import2.AppElement) {
super(
_View_TreeRootComponent_Host0, renderType_TreeRootComponent_Host, import6.ViewType.HOST,
viewUtils, parentInjector, declarationEl, import7.ChangeDetectorStatus.CheckAlways);
}
createInternal(rootSelector: string): import2.AppElement {
this._el_0 = this.selectOrCreateHostElement('tree', rootSelector, (null as any));
this._appEl_0 = new import2.AppElement(0, (null as any), this, this._el_0);
var compView_0: any =
viewFactory_TreeRootComponent0(this.viewUtils, this.injector(0), this._appEl_0);
this._TreeRootComponent_0_4 = new import3.TreeRootComponent();
this._appEl_0.initComponent(this._TreeRootComponent_0_4, [], compView_0);
compView_0.create(this._TreeRootComponent_0_4, this.projectableNodes, (null as any));
this.init([].concat([this._el_0]), [this._el_0], [], []);
return this._appEl_0;
}
injectorGetInternal(token: any, requestNodeIndex: number, notFoundResult: any): any {
if (((token === import3.TreeRootComponent) && (0 === requestNodeIndex))) {
return this._TreeRootComponent_0_4;
}
return notFoundResult;
}
}
function viewFactory_TreeRootComponent_Host0(
viewUtils: import4.ViewUtils, parentInjector: import5.Injector,
declarationEl: import2.AppElement): import1.AppView<any> {
if ((renderType_TreeRootComponent_Host === (null as any))) {
(renderType_TreeRootComponent_Host =
viewUtils.createRenderComponentType('', 0, import8.ViewEncapsulation.None, [], {}));
}
return new _View_TreeRootComponent_Host0(viewUtils, parentInjector, declarationEl);
}
export const TreeRootComponentNgFactory: import9.ComponentFactory<import3.TreeRootComponent> =
new import9.ComponentFactory<import3.TreeRootComponent>(
'tree', viewFactory_TreeRootComponent_Host0, import3.TreeRootComponent);
const styles_TreeRootComponent: any[] = [];
var renderType_TreeRootComponent: import0.RenderComponentType = (null as any);
class _View_TreeRootComponent0 extends import1.AppView<import3.TreeRootComponent> {
_anchor_0: any;
/*private*/ _appEl_0: import2.AppElement;
_TemplateRef_0_5: any;
_NgIf_0_6: import10.NgIf;
/*private*/ _expr_0: any;
constructor(
viewUtils: import4.ViewUtils, parentInjector: import5.Injector,
declarationEl: import2.AppElement) {
super(
_View_TreeRootComponent0, renderType_TreeRootComponent, import6.ViewType.COMPONENT,
viewUtils, parentInjector, declarationEl, import7.ChangeDetectorStatus.CheckAlways);
}
createInternal(rootSelector: string): import2.AppElement {
const parentRenderNode: any =
this.renderer.createViewRoot(this.declarationAppElement.nativeElement);
this._anchor_0 = this.renderer.createTemplateAnchor(parentRenderNode, (null as any));
this._appEl_0 = new import2.AppElement(0, (null as any), this, this._anchor_0);
this._TemplateRef_0_5 =
new import11.TemplateRef_(this._appEl_0, viewFactory_TreeRootComponent1);
this._NgIf_0_6 = new import10.NgIf(this._appEl_0.vcRef, this._TemplateRef_0_5);
this._expr_0 = import7.UNINITIALIZED;
this.init([], [this._anchor_0], [], []);
return (null as any);
}
injectorGetInternal(token: any, requestNodeIndex: number, notFoundResult: any): any {
if (((token === import11.TemplateRef) && (0 === requestNodeIndex))) {
return this._TemplateRef_0_5;
}
if (((token === import10.NgIf) && (0 === requestNodeIndex))) {
return this._NgIf_0_6;
}
return notFoundResult;
}
detectChangesInternal(throwOnChange: boolean): void {
const currVal_0: any = (this.context.data.left != (null as any));
if (import4.checkBinding(throwOnChange, this._expr_0, currVal_0)) {
this._NgIf_0_6.ngIf = currVal_0;
this._expr_0 = currVal_0;
}
this.detectContentChildrenChanges(throwOnChange);
this.detectViewChildrenChanges(throwOnChange);
}
}
export function viewFactory_TreeRootComponent0(
viewUtils: import4.ViewUtils, parentInjector: import5.Injector,
declarationEl: import2.AppElement): import1.AppView<import3.TreeRootComponent> {
if ((renderType_TreeRootComponent === (null as any))) {
(renderType_TreeRootComponent = viewUtils.createRenderComponentType(
'/Users/tbosch/projects/conf-demos/ngc-demo/src/ng2_static/root_tree.ts class TreeRootComponent - inline template',
0, import8.ViewEncapsulation.None, styles_TreeRootComponent, {}));
}
return new _View_TreeRootComponent0(viewUtils, parentInjector, declarationEl);
}
class _View_TreeRootComponent1 extends import1.AppView<any> {
_el_0: any;
_TreeComponent0_0_4View: any;
constructor(
viewUtils: import4.ViewUtils, parentInjector: import5.Injector,
declarationEl: import2.AppElement) {
super(
_View_TreeRootComponent1, renderType_TreeRootComponent, import6.ViewType.EMBEDDED,
viewUtils, parentInjector, declarationEl, import7.ChangeDetectorStatus.CheckAlways);
}
createInternal(rootSelector: string): import2.AppElement {
this._el_0 = this.renderer.createElement((null as any), 'tree0', (null as any));
this._TreeComponent0_0_4View = new import13.View_TreeTreeComponent(maxDepth - 1, this._el_0);
this.init([].concat([this._el_0]), [this._el_0], [], []);
return (null as any);
}
destroyInternal() { this._TreeComponent0_0_4View.destroyInternal(); }
detectChangesInternal(throwOnChange: boolean): void {
this._TreeComponent0_0_4View.updateData(this.parent.context.data);
this.detectContentChildrenChanges(throwOnChange);
this._TreeComponent0_0_4View.detectChangesInternal(throwOnChange);
}
}
function viewFactory_TreeRootComponent1(
viewUtils: import4.ViewUtils, parentInjector: import5.Injector,
declarationEl: import2.AppElement): import1.AppView<any> {
return new _View_TreeRootComponent1(viewUtils, parentInjector, declarationEl);
}

View File

@ -34,7 +34,9 @@ export function openBrowser(config: {
browser.ignoreSynchronization = true;
}
var params = config.params || [];
params = params.concat([{name: 'bundles', value: cmdArgs.bundles}]);
if (!params.some((param) => param.name === 'bundles')) {
params = params.concat([{name: 'bundles', value: cmdArgs.bundles}]);
}
var urlParams: string[] = [];
params.forEach((param) => { urlParams.push(param.name + '=' + param.value); });