refactor (benchmarks/): Ts'ifying benchmarks/

Translating AtScript in benchmarks/ to TypeScript.
This commit is contained in:
Ian Riley 2015-05-29 21:40:15 -07:00 committed by Tobias Bosch
parent 0b43e3cf32
commit 2b60d1bae1
48 changed files with 1590 additions and 1715 deletions

View File

@ -0,0 +1,5 @@
library benchmarks.e2e_test.change_detection_perf;
main() {
}

View File

@ -1,99 +0,0 @@
var perfUtil = require('angular2/src/test_lib/perf_util');
describe('ng2 change detection benchmark', function () {
var URL = 'benchmarks/src/change_detection/change_detection_benchmark.html';
afterEach(perfUtil.verifyNoBrowserErrors);
it('should log ng stats (dynamic, reads)', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#ng2ChangeDetectionDynamicReads'],
id: 'ng2.changeDetection.dynamic.reads',
params: [
{name: 'numberOfChecks', value: 900000},
{name: 'iterations', value: 20, scale: 'linear'}
],
microMetrics: {
'detectChangesAvg': 'avg time to detect changes (ms)'
}
}).then(done, done.fail);
});
it('should log ng stats (dynamic, writes)', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#ng2ChangeDetectionDynamicWrites'],
id: 'ng2.changeDetection.dynamic.writes',
params: [
{name: 'numberOfChecks', value: 900000},
{name: 'iterations', value: 20, scale: 'linear'}
],
microMetrics: {
'detectChangesAvg': 'avg time to detect changes (ms)'
}
}).then(done, done.fail);
});
it('should log ng stats (jit, reads)', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#ng2ChangeDetectionJitReads'],
id: 'ng2.changeDetection.jit.reads',
params: [
{name: 'numberOfChecks', value: 900000},
{name: 'iterations', value: 20, scale: 'linear'}
],
microMetrics: {
'detectChangesAvg': 'avg time to detect changes (ms)'
}
}).then(done, done.fail);
});
it('should log ng stats (jit, writes)', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#ng2ChangeDetectionJitWrites'],
id: 'ng2.changeDetection.jit.writes',
params: [
{name: 'numberOfChecks', value: 900000},
{name: 'iterations', value: 20, scale: 'linear'}
],
microMetrics: {
'detectChangesAvg': 'avg time to detect changes (ms)'
}
}).then(done, done.fail);
});
it('should log baseline stats (create)', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#baselineChangeDetectionReads'],
id: 'baseline.changeDetection.reads',
params: [
{name: 'numberOfChecks', value: 900000},
{name: 'iterations', value: 20, scale: 'linear'}
],
microMetrics: {
'detectChangesAvg': 'avg time to detect changes (ms)'
}
}).then(done, done.fail);
});
it('should log baseline stats (update)', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#baselineChangeDetectionWrites'],
id: 'baseline.changeDetection.writes',
params: [
{name: 'numberOfChecks', value: 900000},
{name: 'iterations', value: 20, scale: 'linear'}
],
microMetrics: {
'detectChangesAvg': 'avg time to detect changes (ms)'
}
}).then(done, done.fail);
});
});

View File

@ -0,0 +1,96 @@
/// <reference path="../../angular2/typings/node/node.d.ts" />
import {afterEach, describe, it} from 'angular2/test_lib';
var perfUtil = require('angular2/src/test_lib/perf_util');
describe('ng2 change detection benchmark', function() {
var URL = 'benchmarks/src/change_detection/change_detection_benchmark.html';
afterEach(perfUtil.verifyNoBrowserErrors);
it('should log ng stats (dynamic, reads)', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#ng2ChangeDetectionDynamicReads'],
id: 'ng2.changeDetection.dynamic.reads',
params: [
{name: 'numberOfChecks', value: 900000},
{name: 'iterations', value: 20, scale: 'linear'}
],
microMetrics: {'detectChangesAvg': 'avg time to detect changes (ms)'}
})
.then(done, done.fail);
});
it('should log ng stats (dynamic, writes)', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#ng2ChangeDetectionDynamicWrites'],
id: 'ng2.changeDetection.dynamic.writes',
params: [
{name: 'numberOfChecks', value: 900000},
{name: 'iterations', value: 20, scale: 'linear'}
],
microMetrics: {'detectChangesAvg': 'avg time to detect changes (ms)'}
})
.then(done, done.fail);
});
it('should log ng stats (jit, reads)', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#ng2ChangeDetectionJitReads'],
id: 'ng2.changeDetection.jit.reads',
params: [
{name: 'numberOfChecks', value: 900000},
{name: 'iterations', value: 20, scale: 'linear'}
],
microMetrics: {'detectChangesAvg': 'avg time to detect changes (ms)'}
})
.then(done, done.fail);
});
it('should log ng stats (jit, writes)', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#ng2ChangeDetectionJitWrites'],
id: 'ng2.changeDetection.jit.writes',
params: [
{name: 'numberOfChecks', value: 900000},
{name: 'iterations', value: 20, scale: 'linear'}
],
microMetrics: {'detectChangesAvg': 'avg time to detect changes (ms)'}
})
.then(done, done.fail);
});
it('should log baseline stats (create)', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#baselineChangeDetectionReads'],
id: 'baseline.changeDetection.reads',
params: [
{name: 'numberOfChecks', value: 900000},
{name: 'iterations', value: 20, scale: 'linear'}
],
microMetrics: {'detectChangesAvg': 'avg time to detect changes (ms)'}
})
.then(done, done.fail);
});
it('should log baseline stats (update)', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#baselineChangeDetectionWrites'],
id: 'baseline.changeDetection.writes',
params: [
{name: 'numberOfChecks', value: 900000},
{name: 'iterations', value: 20, scale: 'linear'}
],
microMetrics: {'detectChangesAvg': 'avg time to detect changes (ms)'}
})
.then(done, done.fail);
});
});

View File

@ -0,0 +1,5 @@
library benchmarks.e2e_test.compiler_perf;
main() {
}

View File

@ -1,37 +0,0 @@
var perfUtil = require('angular2/src/test_lib/perf_util');
describe('ng2 compiler benchmark', function () {
var URL = 'benchmarks/src/compiler/compiler_benchmark.html';
afterEach(perfUtil.verifyNoBrowserErrors);
it('should log withBindings stats', function(done) {
perfUtil.runBenchmark({
url: URL,
id: 'ng2.compile.withBindings',
params: [{
name: 'elements', value: 150, scale: 'linear'
}],
work: function() {
browser.executeScript('document.querySelector("#compileWithBindings").click()');
browser.sleep(500);
}
}).then(done, done.fail);
});
it('should log noBindings stats', function(done) {
perfUtil.runBenchmark({
url: URL,
id: 'ng2.compile.noBindings',
params: [{
name: 'elements', value: 150, scale: 'linear'
}],
work: function() {
browser.executeScript('document.querySelector("#compileNoBindings").click()');
browser.sleep(500);
}
}).then(done, done.fail);
});
});

View File

@ -0,0 +1,39 @@
/// <reference path="../../angular2/typings/node/node.d.ts" />
/// <reference path="../../angular2/typings/angular-protractor/angular-protractor.d.ts" />
import {afterEach, describe, it} from 'angular2/test_lib';
var perfUtil = require('angular2/src/test_lib/perf_util');
describe('ng2 compiler benchmark', function() {
var URL = 'benchmarks/src/compiler/compiler_benchmark.html';
afterEach(perfUtil.verifyNoBrowserErrors);
it('should log withBindings stats', function(done) {
perfUtil.runBenchmark({
url: URL,
id: 'ng2.compile.withBindings',
params: [{name: 'elements', value: 150, scale: 'linear'}],
work: function() {
browser.executeScript('document.querySelector("#compileWithBindings").click()');
browser.sleep(500);
}
})
.then(done, done.fail);
});
it('should log noBindings stats', function(done) {
perfUtil.runBenchmark({
url: URL,
id: 'ng2.compile.noBindings',
params: [{name: 'elements', value: 150, scale: 'linear'}],
work: function() {
browser.executeScript('document.querySelector("#compileNoBindings").click()');
browser.sleep(500);
}
})
.then(done, done.fail);
});
});

View File

@ -0,0 +1,5 @@
library benchmarks.e2e_test.costs_perf;
main() {
}

View File

@ -1,44 +0,0 @@
var perfUtil = require('angular2/src/test_lib/perf_util');
describe('ng2 cost benchmark', function () {
var URL = 'benchmarks/src/costs/index.html';
// Number of components to create in a single iteration
var benchmarkSize = 200;
afterEach(perfUtil.verifyNoBrowserErrors);
it('should log stats for baseline (plain components)', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#reset', '#createPlainComponents'],
id: 'ng2.costs.baseline',
params: [{
name: 'size', value: benchmarkSize, scale: 'linear'
}]
}).then(done, done.fail);
});
it('should log stats for components with decorators', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#reset', '#createComponentsWithDirectives'],
id: 'ng2.costs.decorators',
params: [{
name: 'size', value: benchmarkSize, scale: 'linear'
}]
}).then(done, done.fail);
});
it('should log stats for dynamic components', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#reset', '#createDynamicComponents'],
id: 'ng2.costs.dynamic',
params: [{
name: 'size', value: benchmarkSize, scale: 'linear'
}]
}).then(done, done.fail);
});
});

View File

@ -0,0 +1,44 @@
/// <reference path="../../angular2/typings/node/node.d.ts" />
import {afterEach, describe, it} from 'angular2/test_lib';
var perfUtil = require('angular2/src/test_lib/perf_util');
describe('ng2 cost benchmark', function() {
var URL = 'benchmarks/src/costs/index.html';
// Number of components to create in a single iteration
var benchmarkSize = 200;
afterEach(perfUtil.verifyNoBrowserErrors);
it('should log stats for baseline (plain components)', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#reset', '#createPlainComponents'],
id: 'ng2.costs.baseline',
params: [{name: 'size', value: benchmarkSize, scale: 'linear'}]
})
.then(done, done.fail);
});
it('should log stats for components with decorators', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#reset', '#createComponentsWithDirectives'],
id: 'ng2.costs.decorators',
params: [{name: 'size', value: benchmarkSize, scale: 'linear'}]
})
.then(done, done.fail);
});
it('should log stats for dynamic components', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#reset', '#createDynamicComponents'],
id: 'ng2.costs.dynamic',
params: [{name: 'size', value: benchmarkSize, scale: 'linear'}]
})
.then(done, done.fail);
});
});

View File

@ -0,0 +1,5 @@
library benchmarks.e2e_test.di_perf;
main() {
}

View File

@ -1,100 +0,0 @@
var perfUtil = require('angular2/src/test_lib/perf_util');
describe('ng2 di benchmark', function () {
var URL = 'benchmarks/src/di/di_benchmark.html';
afterEach(perfUtil.verifyNoBrowserErrors);
it('should log the stats for getByToken', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#getByToken'],
id: 'ng2.di.getByToken',
params: [{
name: 'iterations', value: 20000, scale: 'linear'
}],
microMetrics: {
'injectAvg': 'avg time for injection (in ms)'
}
}).then(done, done.fail);
});
it('should log the stats for getByKey', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#getByKey'],
id: 'ng2.di.getByKey',
params: [{
name: 'iterations', value: 20000, scale: 'linear'
}],
microMetrics: {
'injectAvg': 'avg time for injection (in ms)'
}
}).then(done, done.fail);
});
it('should log the stats for getChild', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#getChild'],
id: 'ng2.di.getChild',
params: [{
name: 'iterations', value: 20000, scale: 'linear'
}],
microMetrics: {
'injectAvg': 'avg time for getChild (in ms)'
}
}).then(done, done.fail);
});
it('should log the stats for instantiate', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#instantiate'],
id: 'ng2.di.instantiate',
params: [{
name: 'iterations', value: 10000, scale: 'linear'
}],
microMetrics: {
'injectAvg': 'avg time for instantiate (in ms)'
}
}).then(done, done.fail);
});
/**
* This benchmark measures the cost of creating a new injector with a mix
* of binding types: Type, unresolved, unflattened.
*/
it('should log the stats for createVariety', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#createVariety'],
id: 'ng2.di.createVariety',
params: [{
name: 'iterations', value: 10000, scale: 'linear'
}],
microMetrics: {
'injectAvg': 'avg time for createVariety (in ms)'
}
}).then(done, done.fail);
});
/**
* Same as 'createVariety' benchmark but operates on fully resolved bindings.
*/
it('should log the stats for createVarietyResolved', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#createVarietyResolved'],
id: 'ng2.di.createVarietyResolved',
params: [{
name: 'iterations', value: 10000, scale: 'linear'
}],
microMetrics: {
'injectAvg': 'avg time for createVarietyResolved (in ms)'
}
}).then(done, done.fail);
});
});

View File

@ -0,0 +1,85 @@
/// <reference path="../../angular2/typings/node/node.d.ts" />
import {afterEach, describe, it} from 'angular2/test_lib';
var perfUtil = require('angular2/src/test_lib/perf_util');
describe('ng2 di benchmark', function() {
var URL = 'benchmarks/src/di/di_benchmark.html';
afterEach(perfUtil.verifyNoBrowserErrors);
it('should log the stats for getByToken', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#getByToken'],
id: 'ng2.di.getByToken',
params: [{name: 'iterations', value: 20000, scale: 'linear'}],
microMetrics: {'injectAvg': 'avg time for injection (in ms)'}
})
.then(done, done.fail);
});
it('should log the stats for getByKey', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#getByKey'],
id: 'ng2.di.getByKey',
params: [{name: 'iterations', value: 20000, scale: 'linear'}],
microMetrics: {'injectAvg': 'avg time for injection (in ms)'}
})
.then(done, done.fail);
});
it('should log the stats for getChild', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#getChild'],
id: 'ng2.di.getChild',
params: [{name: 'iterations', value: 20000, scale: 'linear'}],
microMetrics: {'injectAvg': 'avg time for getChild (in ms)'}
})
.then(done, done.fail);
});
it('should log the stats for instantiate', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#instantiate'],
id: 'ng2.di.instantiate',
params: [{name: 'iterations', value: 10000, scale: 'linear'}],
microMetrics: {'injectAvg': 'avg time for instantiate (in ms)'}
})
.then(done, done.fail);
});
/**
* This benchmark measures the cost of creating a new injector with a mix
* of binding types: Type, unresolved, unflattened.
*/
it('should log the stats for createVariety', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#createVariety'],
id: 'ng2.di.createVariety',
params: [{name: 'iterations', value: 10000, scale: 'linear'}],
microMetrics: {'injectAvg': 'avg time for createVariety (in ms)'}
})
.then(done, done.fail);
});
/**
* Same as 'createVariety' benchmark but operates on fully resolved bindings.
*/
it('should log the stats for createVarietyResolved', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#createVarietyResolved'],
id: 'ng2.di.createVarietyResolved',
params: [{name: 'iterations', value: 10000, scale: 'linear'}],
microMetrics: {'injectAvg': 'avg time for createVarietyResolved (in ms)'}
})
.then(done, done.fail);
});
});

View File

@ -0,0 +1,5 @@
library benchmarks.e2e_test.element_injector_perf;
main() {
}

View File

@ -1,37 +0,0 @@
var perfUtil = require('angular2/src/test_lib/perf_util');
describe('ng2 element injector benchmark', function () {
var URL = 'benchmarks/src/element_injector/element_injector_benchmark.html';
afterEach(perfUtil.verifyNoBrowserErrors);
it('should log the stats for instantiate', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#instantiate'],
id: 'ng2.elementInjector.instantiate',
params: [{
name: 'iterations', value: 20000, scale: 'linear'
}],
microMetrics: {
'instantiateAvg': 'avg time for injection (in ms)'
}
}).then(done, done.fail);
});
it('should log the stats for hydrate', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#hydrate'],
id: 'ng2.elementInjector.hydrate',
params: [{
name: 'iterations', value: 20000, scale: 'linear'
}],
microMetrics: {
'instantiateAvg': 'avg time for injection (in ms)'
}
}).then(done, done.fail);
});
});

View File

@ -0,0 +1,34 @@
/// <reference path="../../angular2/typings/node/node.d.ts" />
import {afterEach, describe, it} from 'angular2/test_lib';
var perfUtil = require('angular2/src/test_lib/perf_util');
describe('ng2 element injector benchmark', function() {
var URL = 'benchmarks/src/element_injector/element_injector_benchmark.html';
afterEach(perfUtil.verifyNoBrowserErrors);
it('should log the stats for instantiate', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#instantiate'],
id: 'ng2.elementInjector.instantiate',
params: [{name: 'iterations', value: 20000, scale: 'linear'}],
microMetrics: {'instantiateAvg': 'avg time for injection (in ms)'}
})
.then(done, done.fail);
});
it('should log the stats for hydrate', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#hydrate'],
id: 'ng2.elementInjector.hydrate',
params: [{name: 'iterations', value: 20000, scale: 'linear'}],
microMetrics: {'instantiateAvg': 'avg time for injection (in ms)'}
})
.then(done, done.fail);
});
});

View File

@ -0,0 +1,5 @@
library benchmarks.e2e_test.largetable_perf;
main() {
}

View File

@ -1,64 +0,0 @@
var perfUtil = require('angular2/src/test_lib/perf_util');
describe('ng2 largetable benchmark', function () {
var URL = 'benchmarks/src/largetable/largetable_benchmark.html';
afterEach(perfUtil.verifyNoBrowserErrors);
// Not yet implemented:
// 'ngBind',
// 'ngBindOnce',
// 'ngBindFn',
// 'ngBindFilter',
// 'interpolationFilter'
[
'interpolation',
'interpolationAttr',
'interpolationFn'
].forEach(function(benchmarkType) {
it('should log the ng stats with: ' + benchmarkType, function(done) {
console.log('executing for type', benchmarkType);
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#ng2DestroyDom', '#ng2CreateDom'],
id: 'ng2.largetable.' + benchmarkType,
params: [{
name: 'rows',
value: 20,
scale: 'sqrt'
},{
name: 'columns',
value: 20,
scale: 'sqrt'
},{
name: 'benchmarkType',
value: benchmarkType
}]
}).then(done, done.fail);
});
});
it('should log the baseline stats', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#baselineDestroyDom', '#baselineCreateDom'],
id: 'baseline.largetable',
params: [{
name: 'rows',
value: 100,
scale: 'sqrt'
},{
name: 'columns',
value: 20,
scale: 'sqrt'
},{
name: 'benchmarkType',
value: 'baseline'
}]
}).then(done, done.fail);;
});
});

View File

@ -0,0 +1,52 @@
/// <reference path="../../angular2/typings/node/node.d.ts" />
import {afterEach, describe, it} from 'angular2/test_lib';
var perfUtil = require('angular2/src/test_lib/perf_util');
describe('ng2 largetable benchmark', function() {
var URL = 'benchmarks/src/largetable/largetable_benchmark.html';
afterEach(perfUtil.verifyNoBrowserErrors);
// Not yet implemented:
// 'ngBind',
// 'ngBindOnce',
// 'ngBindFn',
// 'ngBindFilter',
// 'interpolationFilter'
['interpolation', 'interpolationAttr', 'interpolationFn'].forEach(function(benchmarkType) {
it('should log the ng stats with: ' + benchmarkType, function(done) {
console.log('executing for type', benchmarkType);
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#ng2DestroyDom', '#ng2CreateDom'],
id: 'ng2.largetable.' + benchmarkType,
params: [
{name: 'rows', value: 20, scale: 'sqrt'},
{name: 'columns', value: 20, scale: 'sqrt'},
{name: 'benchmarkType', value: benchmarkType}
]
})
.then(done, done.fail);
});
});
it('should log the baseline stats', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#baselineDestroyDom', '#baselineCreateDom'],
id: 'baseline.largetable',
params: [
{name: 'rows', value: 100, scale: 'sqrt'},
{name: 'columns', value: 20, scale: 'sqrt'},
{name: 'benchmarkType', value: 'baseline'}
]
})
.then(done, done.fail);
;
});
});

View File

@ -0,0 +1,5 @@
library benchmarks.e2e_test.naive_infinite_scroll_perf;
main() {
}

View File

@ -1,35 +0,0 @@
var perfUtil = require('angular2/src/test_lib/perf_util');
describe('ng2 naive infinite scroll benchmark', function () {
var URL = 'benchmarks/src/naive_infinite_scroll/index.html';
afterEach(perfUtil.verifyNoBrowserErrors);
[1, 2, 4].forEach(function(appSize) {
it('should run scroll benchmark and collect stats for appSize = ' +
appSize, function(done) {
perfUtil.runBenchmark({
url: URL,
id: 'ng2.naive_infinite_scroll',
work: function() {
$('#reset-btn').click();
$('#run-btn').click();
browser.wait(() => {
return $('#done').getText().then(
function() { return true; },
function() { return false; });
}, 10000);
},
params: [{
name: 'appSize', value: appSize
}, {
name: 'iterationCount', value: 20, scale: 'linear'
}, {
name: 'scrollIncrement', value: 40
}]
}).then(done, done.fail);
});
});
});

View File

@ -0,0 +1,36 @@
/// <reference path="../../angular2/typings/node/node.d.ts" />
/// <reference path="../../angular2/typings/angular-protractor/angular-protractor.d.ts" />
import {afterEach, describe, it} from 'angular2/test_lib';
var perfUtil = require('angular2/src/test_lib/perf_util');
describe('ng2 naive infinite scroll benchmark', function() {
var URL = 'benchmarks/src/naive_infinite_scroll/index.html';
afterEach(perfUtil.verifyNoBrowserErrors);
[1, 2, 4].forEach(function(appSize) {
it('should run scroll benchmark and collect stats for appSize = ' + appSize, function(done) {
perfUtil.runBenchmark({
url: URL,
id: 'ng2.naive_infinite_scroll',
work: function() {
$('#reset-btn').click();
$('#run-btn').click();
browser.wait(() => {
return $('#done').getText().then(function() { return true; },
function() { return false; });
}, 10000);
},
params: [
{name: 'appSize', value: appSize},
{name: 'iterationCount', value: 20, scale: 'linear'},
{name: 'scrollIncrement', value: 40}
]
})
.then(done, done.fail);
});
});
});

View File

@ -0,0 +1,5 @@
library benchmarks.e2e_test.naive_infinite_scroll_spec;
main() {
}

View File

@ -1,65 +0,0 @@
var testUtil = require('angular2/src/test_lib/e2e_util');
describe('ng2 naive infinite scroll benchmark', function () {
var URL = 'benchmarks/src/naive_infinite_scroll/index.html?appSize=3';
afterEach(testUtil.verifyNoBrowserErrors);
it('should not throw errors', function() {
browser.get(URL);
var expectedRowCount = 18;
var expectedCellsPerRow = 28;
var allScrollItems = 'scroll-app #testArea scroll-item';
var cells = `${ allScrollItems } .row *`;
var stageButtons =
`${ allScrollItems } .row stage-buttons button`;
var count = function(selector) {
return browser.executeScript(
`return document.querySelectorAll("${ selector }").length;`
);
}
var clickFirstOf = function(selector) {
return browser.executeScript(
`document.querySelector("${ selector }").click();`
);
}
var firstTextOf = function(selector) {
return browser.executeScript(
`return document.querySelector("${ selector }").innerText;`
);
}
// Make sure rows are rendered
count(allScrollItems).then(function(c) {
expect(c).toBe(expectedRowCount);
});
// Make sure cells are rendered
count(cells).then(function(c) {
expect(c).toBe(expectedRowCount * expectedCellsPerRow);
});
// Click on first enabled button and verify stage changes
firstTextOf(`${ stageButtons }:enabled`).then(function(text) {
expect(text).toBe('Pitched');
clickFirstOf(`${ stageButtons }:enabled`).then(function() {
firstTextOf(`${ stageButtons }:enabled`).then(function(text) {
expect(text).toBe('Won');
})
});
})
$("#reset-btn").click();
$("#run-btn").click();
browser.wait(() => {
return $('#done').getText().then(
function() { return true; },
function() { return false; });
}, 10000);
});
});

View File

@ -0,0 +1,62 @@
/// <reference path="../../angular2/typings/node/node.d.ts" />
/// <reference path="../../angular2/typings/angular-protractor/angular-protractor.d.ts" />
import {afterEach, describe, expect, it} from 'angular2/test_lib';
var testUtil = require('angular2/src/test_lib/e2e_util');
describe('ng2 naive infinite scroll benchmark', function() {
var URL = 'benchmarks/src/naive_infinite_scroll/index.html?appSize=3';
afterEach(testUtil.verifyNoBrowserErrors);
it('should not throw errors', function() {
browser.get(URL);
var expectedRowCount = 18;
var expectedCellsPerRow = 28;
var allScrollItems = 'scroll-app #testArea scroll-item';
var cells = `${ allScrollItems } .row *`;
var stageButtons = `${ allScrollItems } .row stage-buttons button`;
var count =
function(selector) {
return browser.executeScript(`return document.querySelectorAll("${ selector }").length;`);
}
var clickFirstOf =
function(selector) {
return browser.executeScript(`document.querySelector("${ selector }").click();`);
}
var firstTextOf =
function(selector) {
return browser.executeScript(`return document.querySelector("${ selector }").innerText;`);
}
// Make sure rows are rendered
count(allScrollItems)
.then(function(c) { expect(c).toBe(expectedRowCount); });
// Make sure cells are rendered
count(cells).then(function(c) { expect(c).toBe(expectedRowCount * expectedCellsPerRow); });
// Click on first enabled button and verify stage changes
firstTextOf(`${ stageButtons }:enabled`)
.then(function(text) {
expect(text).toBe('Pitched');
clickFirstOf(`${ stageButtons }:enabled`)
.then(function() {
firstTextOf(`${ stageButtons }:enabled`)
.then(function(text) { expect(text).toBe('Won'); })
});
})
$("#reset-btn")
.click();
$("#run-btn").click();
browser.wait(() => {
return $('#done').getText().then(function() { return true; }, function() { return false; });
}, 10000);
});
});

View File

@ -0,0 +1,5 @@
library benchmarks.e2e_test.selector_perf;
main() {
}

View File

@ -1,42 +0,0 @@
var perfUtil = require('angular2/src/test_lib/perf_util');
describe('ng2 selector benchmark', function () {
var URL = 'benchmarks/src/compiler/selector_benchmark.html';
afterEach(perfUtil.verifyNoBrowserErrors);
it('should log parse stats', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#parse'],
id: 'ng2.selector.parse',
params: [{
name: 'selectors', value: 10000, scale: 'linear'
}]
}).then(done, done.fail);
});
it('should log addSelectable stats', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#addSelectable'],
id: 'ng2.selector.addSelectable',
params: [{
name: 'selectors', value: 10000, scale: 'linear'
}]
}).then(done, done.fail);
});
it('should log match stats', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#match'],
id: 'ng2.selector.match',
params: [{
name: 'selectors', value: 10000, scale: 'linear'
}]
}).then(done, done.fail);
});
});

View File

@ -0,0 +1,42 @@
/// <reference path="../../angular2/typings/node/node.d.ts" />
import {afterEach, describe, it} from 'angular2/test_lib';
var perfUtil = require('angular2/src/test_lib/perf_util');
describe('ng2 selector benchmark', function() {
var URL = 'benchmarks/src/compiler/selector_benchmark.html';
afterEach(perfUtil.verifyNoBrowserErrors);
it('should log parse stats', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#parse'],
id: 'ng2.selector.parse',
params: [{name: 'selectors', value: 10000, scale: 'linear'}]
})
.then(done, done.fail);
});
it('should log addSelectable stats', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#addSelectable'],
id: 'ng2.selector.addSelectable',
params: [{name: 'selectors', value: 10000, scale: 'linear'}]
})
.then(done, done.fail);
});
it('should log match stats', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#match'],
id: 'ng2.selector.match',
params: [{name: 'selectors', value: 10000, scale: 'linear'}]
})
.then(done, done.fail);
});
});

View File

@ -0,0 +1,5 @@
library benchmarks.e2e_test.tree_perf;
main() {
}

View File

@ -1,70 +0,0 @@
var perfUtil = require('angular2/src/test_lib/perf_util');
describe('ng2 tree benchmark', function () {
var URL = 'benchmarks/src/tree/tree_benchmark.html';
afterEach(perfUtil.verifyNoBrowserErrors);
it('should log the ng stats with viewcache', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#ng2DestroyDom', '#ng2CreateDom'],
id: 'ng2.tree.create.viewcache',
params: [{
name: 'depth', value: 9, scale: 'log2'
},{
name: 'viewcache', value: 'true'
}]
}).then(done, done.fail);
});
it('should log the ng stats without viewcache', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#ng2DestroyDom', '#ng2CreateDom'],
id: 'ng2.tree.create.plain',
params: [{
name: 'depth', value: 9, scale: 'log2'
},{
name: 'viewcache', value: 'false'
}]
}).then(done, done.fail);
});
it('should log the ng stats (update)', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#ng2CreateDom'],
id: 'ng2.tree.update',
params: [{
name: 'depth', value: 9, scale: 'log2'
},{
name: 'viewcache', value: 'true'
}]
}).then(done, done.fail);
});
it('should log the baseline stats', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#baselineDestroyDom', '#baselineCreateDom'],
id: 'baseline.tree.create',
params: [{
name: 'depth', value: 9, scale: 'log2'
}]
}).then(done, done.fail);
});
it('should log the baseline stats (update)', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#baselineCreateDom'],
id: 'baseline.tree.update',
params: [{
name: 'depth', value: 9, scale: 'log2'
}]
}).then(done, done.fail);
});
});

View File

@ -0,0 +1,65 @@
/// <reference path="../../angular2/typings/node/node.d.ts" />
import {afterEach, describe, it} from 'angular2/test_lib';
var perfUtil = require('angular2/src/test_lib/perf_util');
describe('ng2 tree benchmark', function() {
var URL = 'benchmarks/src/tree/tree_benchmark.html';
afterEach(perfUtil.verifyNoBrowserErrors);
it('should log the ng stats with viewcache', function(done) {
perfUtil
.runClickBenchmark({
url: URL,
buttons: ['#ng2DestroyDom', '#ng2CreateDom'],
id: 'ng2.tree.create.viewcache',
params: [{name: 'depth', value: 9, scale: 'log2'}, {name: 'viewcache', value: 'true'}]
})
.then(done, done.fail);
});
it('should log the ng stats without viewcache', function(done) {
perfUtil
.runClickBenchmark({
url: URL,
buttons: ['#ng2DestroyDom', '#ng2CreateDom'],
id: 'ng2.tree.create.plain',
params: [{name: 'depth', value: 9, scale: 'log2'}, {name: 'viewcache', value: 'false'}]
})
.then(done, done.fail);
});
it('should log the ng stats (update)', function(done) {
perfUtil
.runClickBenchmark({
url: URL,
buttons: ['#ng2CreateDom'],
id: 'ng2.tree.update',
params: [{name: 'depth', value: 9, scale: 'log2'}, {name: 'viewcache', value: 'true'}]
})
.then(done, done.fail);
});
it('should log the baseline stats', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#baselineDestroyDom', '#baselineCreateDom'],
id: 'baseline.tree.create',
params: [{name: 'depth', value: 9, scale: 'log2'}]
})
.then(done, done.fail);
});
it('should log the baseline stats (update)', function(done) {
perfUtil.runClickBenchmark({
url: URL,
buttons: ['#baselineCreateDom'],
id: 'baseline.tree.update',
params: [{name: 'depth', value: 9, scale: 'log2'}]
})
.then(done, done.fail);
});
});

View File

@ -1,320 +0,0 @@
import {reflector} from 'angular2/src/reflection/reflection';
import {isPresent, isJsObject} from 'angular2/src/facade/lang';
import {getIntParameter, bindAction, microBenchmark} from 'angular2/src/test_lib/benchmark_util';
import {BrowserDomAdapter} from 'angular2/src/dom/browser_adapter';
import {
Lexer,
Parser,
ChangeDispatcher,
ChangeDetection,
DynamicChangeDetection,
JitChangeDetection,
ChangeDetectorDefinition,
BindingRecord,
DirectiveRecord,
DirectiveIndex,
DEFAULT
} from 'angular2/change_detection';
// ---- SHARED
class Obj {
field0;
field1;
field2;
field3;
field4;
field5;
field6;
field7;
field8;
field9;
setField(index, value) {
switch (index) {
case 0: this.field0 = value; break;
case 1: this.field1 = value; break;
case 2: this.field2 = value; break;
case 3: this.field3 = value; break;
case 4: this.field4 = value; break;
case 5: this.field5 = value; break;
case 6: this.field6 = value; break;
case 7: this.field7 = value; break;
case 8: this.field8 = value; break;
case 9: this.field9 = value; break;
}
}
getField(index) {
switch (index) {
case 0: return this.field0;
case 1: return this.field1;
case 2: return this.field2;
case 3: return this.field3;
case 4: return this.field4;
case 5: return this.field5;
case 6: return this.field6;
case 7: return this.field7;
case 8: return this.field8;
case 9: return this.field9;
}
}
}
class Row {
obj;
targetObj;
field0;
field1;
field2;
field3;
field4;
field5;
field6;
field7;
field8;
field9;
next;
}
function createObject() {
var obj = new Obj();
for (var i = 0; i < 10; ++i) {
obj.setField(i, i);
}
return obj;
}
function changeObject(object) {
for (var i = 0; i < 10; ++i) {
object.setField(i, object.getField(i) + 1);
}
}
function setUpReflector() {
reflector.registerGetters({
'field0': function(obj){return obj.field0},
'field1': function(obj){return obj.field1},
'field2': function(obj){return obj.field2},
'field3': function(obj){return obj.field3},
'field4': function(obj){return obj.field4},
'field5': function(obj){return obj.field5},
'field6': function(obj){return obj.field6},
'field7': function(obj){return obj.field7},
'field8': function(obj){return obj.field8},
'field9': function(obj){return obj.field9}
});
reflector.registerSetters({
'field0': function(obj, v){return obj.field0 = v},
'field1': function(obj, v){return obj.field1 = v},
'field2': function(obj, v){return obj.field2 = v},
'field3': function(obj, v){return obj.field3 = v},
'field4': function(obj, v){return obj.field4 = v},
'field5': function(obj, v){return obj.field5 = v},
'field6': function(obj, v){return obj.field6 = v},
'field7': function(obj, v){return obj.field7 = v},
'field8': function(obj, v){return obj.field8 = v},
'field9': function(obj, v){return obj.field9 = v}
});
}
// ---- BASELINE
function setUpBaseline(iterations, object) {
function createRow(i) {
var r = new Row();
r.obj = object;
r.targetObj = new Obj();
return r;
}
var head = createRow(0);
var current = head;
for (var i = 1; i < iterations; i++) {
var newRow = createRow(i);
current.next = newRow;
current = newRow;
}
return head;
}
function checkBaselineRow(r) {
var obj = r.obj;
if (obj.field0 !== r.field0) {r.field0 = obj.field0; r.targetObj.field0 = obj.field0; }
if (obj.field1 !== r.field1) {r.field1 = obj.field1; r.targetObj.field1 = obj.field1; }
if (obj.field2 !== r.field2) {r.field2 = obj.field2; r.targetObj.field2 = obj.field2; }
if (obj.field3 !== r.field3) {r.field3 = obj.field3; r.targetObj.field3 = obj.field3; }
if (obj.field4 !== r.field4) {r.field4 = obj.field4; r.targetObj.field4 = obj.field4; }
if (obj.field5 !== r.field5) {r.field5 = obj.field5; r.targetObj.field5 = obj.field5; }
if (obj.field6 !== r.field6) {r.field6 = obj.field6; r.targetObj.field6 = obj.field6; }
if (obj.field7 !== r.field7) {r.field7 = obj.field7; r.targetObj.field7 = obj.field7; }
if (obj.field8 !== r.field8) {r.field8 = obj.field8; r.targetObj.field8 = obj.field8; }
if (obj.field9 !== r.field9) {r.field9 = obj.field9; r.targetObj.field9 = obj.field9; }
}
function runBaselineChangeDetection(baselineHead){
var current = baselineHead;
while (isPresent(current)) {
checkBaselineRow(current);
current = current.next;
}
}
function runBaselineReads(baselineHead, numberOfRuns) {
for (var i = 0; i < numberOfRuns; ++i) {
runBaselineChangeDetection(baselineHead);
}
}
function runBaselineWrites(baselineHead, numberOfRuns, object) {
for (var i = 0; i < numberOfRuns; ++i) {
changeObject(object);
runBaselineChangeDetection(baselineHead);
}
}
// ---- CHANGE DETECTION
function setUpChangeDetection(changeDetection:ChangeDetection, iterations, object) {
var dispatcher = new DummyDispatcher();
var parser = new Parser(new Lexer());
var parentProto = changeDetection.createProtoChangeDetector(new ChangeDetectorDefinition('parent', null, [], [], []));
var parentCd = parentProto.instantiate(dispatcher);
var directiveRecord = new DirectiveRecord({directiveIndex: new DirectiveIndex(0, 0)});
var bindings = [
BindingRecord.createForDirective(parser.parseBinding('field0', null), "field0", reflector.setter("field0"), directiveRecord),
BindingRecord.createForDirective(parser.parseBinding('field1', null), "field1", reflector.setter("field1"), directiveRecord),
BindingRecord.createForDirective(parser.parseBinding('field2', null), "field2", reflector.setter("field2"), directiveRecord),
BindingRecord.createForDirective(parser.parseBinding('field3', null), "field3", reflector.setter("field3"), directiveRecord),
BindingRecord.createForDirective(parser.parseBinding('field4', null), "field4", reflector.setter("field4"), directiveRecord),
BindingRecord.createForDirective(parser.parseBinding('field5', null), "field5", reflector.setter("field5"), directiveRecord),
BindingRecord.createForDirective(parser.parseBinding('field6', null), "field6", reflector.setter("field6"), directiveRecord),
BindingRecord.createForDirective(parser.parseBinding('field7', null), "field7", reflector.setter("field7"), directiveRecord),
BindingRecord.createForDirective(parser.parseBinding('field8', null), "field8", reflector.setter("field8"), directiveRecord),
BindingRecord.createForDirective(parser.parseBinding('field9', null), "field9", reflector.setter("field9"), directiveRecord)
];
var proto = changeDetection.createProtoChangeDetector(new ChangeDetectorDefinition("proto", null, [], bindings, [directiveRecord]));
var targetObj = new Obj();
for (var i = 0; i < iterations; ++i) {
var cd = proto.instantiate(dispatcher);
cd.hydrate(object, null, new FakeDirectives(targetObj));
parentCd.addChild(cd);
}
return parentCd;
}
function runChangeDetectionReads(changeDetector, numberOfRuns) {
for(var i = 0; i < numberOfRuns; ++i) {
changeDetector.detectChanges();
}
}
function runChangeDetectionWrites(changeDetector, numberOfRuns, object) {
for(var i = 0; i < numberOfRuns; ++i) {
changeObject(object);
changeDetector.detectChanges();
}
}
export function main () {
BrowserDomAdapter.makeCurrent();
var numberOfChecks = getIntParameter('numberOfChecks');
var numberOfRuns = getIntParameter('iterations');
var numberOfChecksPerDetector = 10;
var numberOfDetectors = numberOfChecks / numberOfChecksPerDetector / numberOfRuns;
setUpReflector();
var object = createObject()
// -- BASELINE
var baselineHead = setUpBaseline(numberOfDetectors, object);
runBaselineReads(baselineHead, 1); //warmup
bindAction(
'#baselineChangeDetectionReads',
() => microBenchmark('detectChangesAvg', numberOfRuns, () => runBaselineReads(baselineHead, numberOfRuns))
);
bindAction(
'#baselineChangeDetectionWrites',
() => microBenchmark('detectChangesAvg', numberOfRuns, () => runBaselineWrites(baselineHead, numberOfRuns, object))
);
// -- DYNAMIC
var ng2DynamicChangeDetector = setUpChangeDetection(new DynamicChangeDetection(null), numberOfDetectors, object);
runChangeDetectionReads(ng2DynamicChangeDetector, 1); //warmup
bindAction(
'#ng2ChangeDetectionDynamicReads',
() => microBenchmark('detectChangesAvg', numberOfRuns, () => runChangeDetectionReads(ng2DynamicChangeDetector, numberOfRuns))
);
bindAction(
'#ng2ChangeDetectionDynamicWrites',
() => microBenchmark('detectChangesAvg', numberOfRuns, () => runChangeDetectionWrites(ng2DynamicChangeDetector, numberOfRuns, object))
);
// -- JIT
// Reenable when we have transformers for Dart
if (isJsObject({})) {
var ng2JitChangeDetector = setUpChangeDetection(new JitChangeDetection(null), numberOfDetectors, object);
runChangeDetectionReads(ng2JitChangeDetector, 1); //warmup
bindAction(
'#ng2ChangeDetectionJitReads',
() => microBenchmark('detectChangesAvg', numberOfRuns, () => runChangeDetectionReads(ng2JitChangeDetector, numberOfRuns))
);
bindAction(
'#ng2ChangeDetectionJitWrites',
() => microBenchmark('detectChangesAvg', numberOfRuns, () => runChangeDetectionWrites(ng2JitChangeDetector, numberOfRuns, object))
);
} else {
bindAction('#ng2ChangeDetectionJitReads', () => {});
bindAction('#ng2ChangeDetectionJitWrites', () => {});
}
}
class FakeDirectives {
targetObj:Obj;
constructor(targetObj) {
this.targetObj = targetObj;
}
getDirectiveFor(record) {
return this.targetObj;
}
}
class DummyDispatcher extends ChangeDispatcher {
notifyOnBinding(bindingRecord, newValue) {
throw "Should not be used";
}
}

View File

@ -0,0 +1,383 @@
import {reflector} from 'angular2/src/reflection/reflection';
import {isPresent, isJsObject} from 'angular2/src/facade/lang';
import {getIntParameter, bindAction, microBenchmark} from 'angular2/src/test_lib/benchmark_util';
import {BrowserDomAdapter} from 'angular2/src/dom/browser_adapter';
import {
Lexer,
Parser,
ChangeDispatcher,
ChangeDetection,
DynamicChangeDetection,
JitChangeDetection,
ChangeDetectorDefinition,
BindingRecord,
DirectiveRecord,
DirectiveIndex,
DEFAULT
} from 'angular2/change_detection';
// ---- SHARED
class Obj {
field0;
field1;
field2;
field3;
field4;
field5;
field6;
field7;
field8;
field9;
setField(index, value) {
switch (index) {
case 0:
this.field0 = value;
break;
case 1:
this.field1 = value;
break;
case 2:
this.field2 = value;
break;
case 3:
this.field3 = value;
break;
case 4:
this.field4 = value;
break;
case 5:
this.field5 = value;
break;
case 6:
this.field6 = value;
break;
case 7:
this.field7 = value;
break;
case 8:
this.field8 = value;
break;
case 9:
this.field9 = value;
break;
}
}
getField(index) {
switch (index) {
case 0:
return this.field0;
case 1:
return this.field1;
case 2:
return this.field2;
case 3:
return this.field3;
case 4:
return this.field4;
case 5:
return this.field5;
case 6:
return this.field6;
case 7:
return this.field7;
case 8:
return this.field8;
case 9:
return this.field9;
}
}
}
class Row {
obj;
targetObj;
field0;
field1;
field2;
field3;
field4;
field5;
field6;
field7;
field8;
field9;
next;
}
function createObject() {
var obj = new Obj();
for (var i = 0; i < 10; ++i) {
obj.setField(i, i);
}
return obj;
}
function changeObject(object) {
for (var i = 0; i < 10; ++i) {
object.setField(i, object.getField(i) + 1);
}
}
function setUpReflector() {
reflector.registerGetters({
'field0': function(obj) { return obj.field0 },
'field1': function(obj) { return obj.field1 },
'field2': function(obj) { return obj.field2 },
'field3': function(obj) { return obj.field3 },
'field4': function(obj) { return obj.field4 },
'field5': function(obj) { return obj.field5 },
'field6': function(obj) { return obj.field6 },
'field7': function(obj) { return obj.field7 },
'field8': function(obj) { return obj.field8 },
'field9': function(obj) { return obj.field9 }
});
reflector.registerSetters({
'field0': function(obj, v) { return obj.field0 = v },
'field1': function(obj, v) { return obj.field1 = v },
'field2': function(obj, v) { return obj.field2 = v },
'field3': function(obj, v) { return obj.field3 = v },
'field4': function(obj, v) { return obj.field4 = v },
'field5': function(obj, v) { return obj.field5 = v },
'field6': function(obj, v) { return obj.field6 = v },
'field7': function(obj, v) { return obj.field7 = v },
'field8': function(obj, v) { return obj.field8 = v },
'field9': function(obj, v) { return obj.field9 = v }
});
}
// ---- BASELINE
function setUpBaseline(iterations, object) {
function createRow(i) {
var r = new Row();
r.obj = object;
r.targetObj = new Obj();
return r;
}
var head = createRow(0);
var current = head;
for (var i = 1; i < iterations; i++) {
var newRow = createRow(i);
current.next = newRow;
current = newRow;
}
return head;
}
function checkBaselineRow(r) {
var obj = r.obj;
if (obj.field0 !== r.field0) {
r.field0 = obj.field0;
r.targetObj.field0 = obj.field0;
}
if (obj.field1 !== r.field1) {
r.field1 = obj.field1;
r.targetObj.field1 = obj.field1;
}
if (obj.field2 !== r.field2) {
r.field2 = obj.field2;
r.targetObj.field2 = obj.field2;
}
if (obj.field3 !== r.field3) {
r.field3 = obj.field3;
r.targetObj.field3 = obj.field3;
}
if (obj.field4 !== r.field4) {
r.field4 = obj.field4;
r.targetObj.field4 = obj.field4;
}
if (obj.field5 !== r.field5) {
r.field5 = obj.field5;
r.targetObj.field5 = obj.field5;
}
if (obj.field6 !== r.field6) {
r.field6 = obj.field6;
r.targetObj.field6 = obj.field6;
}
if (obj.field7 !== r.field7) {
r.field7 = obj.field7;
r.targetObj.field7 = obj.field7;
}
if (obj.field8 !== r.field8) {
r.field8 = obj.field8;
r.targetObj.field8 = obj.field8;
}
if (obj.field9 !== r.field9) {
r.field9 = obj.field9;
r.targetObj.field9 = obj.field9;
}
}
function runBaselineChangeDetection(baselineHead) {
var current = baselineHead;
while (isPresent(current)) {
checkBaselineRow(current);
current = current.next;
}
}
function runBaselineReads(baselineHead, numberOfRuns) {
for (var i = 0; i < numberOfRuns; ++i) {
runBaselineChangeDetection(baselineHead);
}
}
function runBaselineWrites(baselineHead, numberOfRuns, object) {
for (var i = 0; i < numberOfRuns; ++i) {
changeObject(object);
runBaselineChangeDetection(baselineHead);
}
}
// ---- CHANGE DETECTION
function setUpChangeDetection(changeDetection: ChangeDetection, iterations, object) {
var dispatcher = new DummyDispatcher();
var parser = new Parser(new Lexer());
var parentProto = changeDetection.createProtoChangeDetector(
new ChangeDetectorDefinition('parent', null, [], [], []));
var parentCd = parentProto.instantiate(dispatcher);
var directiveRecord = new DirectiveRecord({directiveIndex: new DirectiveIndex(0, 0)});
var bindings = [
BindingRecord.createForDirective(parser.parseBinding('field0', null), "field0",
reflector.setter("field0"), directiveRecord),
BindingRecord.createForDirective(parser.parseBinding('field1', null), "field1",
reflector.setter("field1"), directiveRecord),
BindingRecord.createForDirective(parser.parseBinding('field2', null), "field2",
reflector.setter("field2"), directiveRecord),
BindingRecord.createForDirective(parser.parseBinding('field3', null), "field3",
reflector.setter("field3"), directiveRecord),
BindingRecord.createForDirective(parser.parseBinding('field4', null), "field4",
reflector.setter("field4"), directiveRecord),
BindingRecord.createForDirective(parser.parseBinding('field5', null), "field5",
reflector.setter("field5"), directiveRecord),
BindingRecord.createForDirective(parser.parseBinding('field6', null), "field6",
reflector.setter("field6"), directiveRecord),
BindingRecord.createForDirective(parser.parseBinding('field7', null), "field7",
reflector.setter("field7"), directiveRecord),
BindingRecord.createForDirective(parser.parseBinding('field8', null), "field8",
reflector.setter("field8"), directiveRecord),
BindingRecord.createForDirective(parser.parseBinding('field9', null), "field9",
reflector.setter("field9"), directiveRecord)
];
var proto = changeDetection.createProtoChangeDetector(
new ChangeDetectorDefinition("proto", null, [], bindings, [directiveRecord]));
var targetObj = new Obj();
for (var i = 0; i < iterations; ++i) {
var cd = proto.instantiate(dispatcher);
cd.hydrate(object, null, new FakeDirectives(targetObj));
parentCd.addChild(cd);
}
return parentCd;
}
function runChangeDetectionReads(changeDetector, numberOfRuns) {
for (var i = 0; i < numberOfRuns; ++i) {
changeDetector.detectChanges();
}
}
function runChangeDetectionWrites(changeDetector, numberOfRuns, object) {
for (var i = 0; i < numberOfRuns; ++i) {
changeObject(object);
changeDetector.detectChanges();
}
}
export function main() {
BrowserDomAdapter.makeCurrent();
var numberOfChecks = getIntParameter('numberOfChecks');
var numberOfRuns = getIntParameter('iterations');
var numberOfChecksPerDetector = 10;
var numberOfDetectors = numberOfChecks / numberOfChecksPerDetector / numberOfRuns;
setUpReflector();
var object = createObject()
// -- BASELINE
var baselineHead = setUpBaseline(numberOfDetectors, object);
runBaselineReads(baselineHead, 1); // warmup
bindAction('#baselineChangeDetectionReads',
() => microBenchmark('detectChangesAvg', numberOfRuns,
() => runBaselineReads(baselineHead, numberOfRuns)));
bindAction('#baselineChangeDetectionWrites',
() => microBenchmark('detectChangesAvg', numberOfRuns,
() => runBaselineWrites(baselineHead, numberOfRuns, object)));
// -- DYNAMIC
var ng2DynamicChangeDetector =
setUpChangeDetection(new DynamicChangeDetection(null), numberOfDetectors, object);
runChangeDetectionReads(ng2DynamicChangeDetector, 1); // warmup
bindAction(
'#ng2ChangeDetectionDynamicReads',
() => microBenchmark('detectChangesAvg', numberOfRuns,
() => runChangeDetectionReads(ng2DynamicChangeDetector, numberOfRuns)));
bindAction('#ng2ChangeDetectionDynamicWrites',
() => microBenchmark(
'detectChangesAvg', numberOfRuns,
() => runChangeDetectionWrites(ng2DynamicChangeDetector, numberOfRuns, object)));
// -- JIT
// Reenable when we have transformers for Dart
if (isJsObject({})) {
var ng2JitChangeDetector =
setUpChangeDetection(new JitChangeDetection(null), numberOfDetectors, object);
runChangeDetectionReads(ng2JitChangeDetector, 1); // warmup
bindAction(
'#ng2ChangeDetectionJitReads',
() => microBenchmark('detectChangesAvg', numberOfRuns,
() => runChangeDetectionReads(ng2JitChangeDetector, numberOfRuns)));
bindAction('#ng2ChangeDetectionJitWrites',
() => microBenchmark(
'detectChangesAvg', numberOfRuns,
() => runChangeDetectionWrites(ng2JitChangeDetector, numberOfRuns, object)));
} else {
bindAction('#ng2ChangeDetectionJitReads', () => {});
bindAction('#ng2ChangeDetectionJitWrites', () => {});
}
}
class FakeDirectives {
targetObj: Obj;
constructor(targetObj) { this.targetObj = targetObj; }
getDirectiveFor(record) { return this.targetObj; }
}
class DummyDispatcher extends ChangeDispatcher {
notifyOnBinding(bindingRecord, newValue) { throw "Should not be used"; }
}

View File

@ -1,17 +1,17 @@
import {BrowserDomAdapter} from 'angular2/src/dom/browser_adapter'; import {BrowserDomAdapter} from 'angular2/src/dom/browser_adapter';
import {PromiseWrapper} from 'angular2/src/facade/async'; import {PromiseWrapper} from 'angular2/src/facade/async';
import {ListWrapper, MapWrapper} from 'angular2/src/facade/collection'; import {List, ListWrapper, Map, MapWrapper} from 'angular2/src/facade/collection';
import {DateWrapper, Type, print} from 'angular2/src/facade/lang'; import {DateWrapper, Type, print} from 'angular2/src/facade/lang';
import {NativeShadowDomStrategy} from 'angular2/src/render/dom/shadow_dom/native_shadow_dom_strategy'; import {
NativeShadowDomStrategy
} from 'angular2/src/render/dom/shadow_dom/native_shadow_dom_strategy';
import {Parser, Lexer, DynamicChangeDetection} from 'angular2/change_detection'; import {Parser, Lexer, DynamicChangeDetection} from 'angular2/change_detection';
import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler'; import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler';
import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver'; import {DirectiveResolver} from 'angular2/src/core/compiler/directive_resolver';
import {Component} from 'angular2/src/core/annotations_impl/annotations'; import {Component, Directive, View} from 'angular2/angular2';
import {Directive} from 'angular2/src/core/annotations_impl/annotations';
import {View} from 'angular2/src/core/annotations_impl/view';
import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader'; import {TemplateLoader} from 'angular2/src/render/dom/compiler/template_loader';
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver'; import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
import {UrlResolver} from 'angular2/src/services/url_resolver'; import {UrlResolver} from 'angular2/src/services/url_resolver';
@ -37,26 +37,18 @@ export function main() {
var urlResolver = new UrlResolver(); var urlResolver = new UrlResolver();
var styleUrlResolver = new StyleUrlResolver(urlResolver); var styleUrlResolver = new StyleUrlResolver(urlResolver);
var shadowDomStrategy = new NativeShadowDomStrategy(styleUrlResolver); var shadowDomStrategy = new NativeShadowDomStrategy(styleUrlResolver);
var renderCompiler = new rc.DefaultDomCompiler( var renderCompiler = new rc.DefaultDomCompiler(new Parser(new Lexer()), shadowDomStrategy,
new Parser(new Lexer()), shadowDomStrategy, new TemplateLoader(null, urlResolver) new TemplateLoader(null, urlResolver));
); var compiler =
var compiler = new Compiler( new Compiler(reader, cache, templateResolver, new ComponentUrlMapper(), urlResolver,
reader, renderCompiler, new ProtoViewFactory(new DynamicChangeDetection(null)));
cache,
templateResolver,
new ComponentUrlMapper(),
urlResolver,
renderCompiler,
new ProtoViewFactory(new DynamicChangeDetection(null))
);
function measureWrapper(func, desc) { function measureWrapper(func, desc) {
return function() { return function() {
var begin = DateWrapper.now(); var begin = DateWrapper.now();
print(`[${desc}] Begin...`); print(`[${desc}] Begin...`);
var onSuccess = function(_) { var onSuccess = function(_) {
var elapsedMs = DateWrapper.toMillis( var elapsedMs = DateWrapper.toMillis(DateWrapper.now()) - DateWrapper.toMillis(begin);
DateWrapper.now()) - DateWrapper.toMillis(begin);
print(`[${desc}] ...done, took ${elapsedMs} ms`); print(`[${desc}] ...done, took ${elapsedMs} ms`);
}; };
PromiseWrapper.then(func(), onSuccess, null); PromiseWrapper.then(func(), onSuccess, null);
@ -73,65 +65,39 @@ export function main() {
return compiler.compile(BenchmarkComponentWithBindings); return compiler.compile(BenchmarkComponentWithBindings);
} }
bindAction('#compileNoBindings', bindAction('#compileNoBindings', measureWrapper(compileNoBindings, 'No Bindings'));
measureWrapper(compileNoBindings, 'No Bindings')); bindAction('#compileWithBindings', measureWrapper(compileWithBindings, 'With Bindings'));
bindAction('#compileWithBindings',
measureWrapper(compileWithBindings, 'With Bindings'));
} }
@Directive({ @Directive({selector: '[dir0]', properties: ['prop: attr0']})
selector: '[dir0]', class Dir0 {
properties: [ }
'prop: attr0'
]
})
class Dir0 {}
@Directive({ @Directive({selector: '[dir1]', properties: ['prop: attr1']})
selector: '[dir1]',
properties: [
'prop: attr1'
]
})
class Dir1 { class Dir1 {
constructor(dir0:Dir0) {} constructor(dir0: Dir0) {}
} }
@Directive({ @Directive({selector: '[dir2]', properties: ['prop: attr2']})
selector: '[dir2]',
properties: [
'prop: attr2'
]
})
class Dir2 { class Dir2 {
constructor(dir1:Dir1) {} constructor(dir1: Dir1) {}
} }
@Directive({ @Directive({selector: '[dir3]', properties: ['prop: attr3']})
selector: '[dir3]',
properties: [
'prop: attr3'
]
})
class Dir3 { class Dir3 {
constructor(dir2:Dir2) {} constructor(dir2: Dir2) {}
} }
@Directive({ @Directive({selector: '[dir4]', properties: ['prop: attr4']})
selector: '[dir4]',
properties: [
'prop: attr4'
]
})
class Dir4 { class Dir4 {
constructor(dir3:Dir3) {} constructor(dir3: Dir3) {}
} }
class MultipleTemplateResolver extends TemplateResolver { class MultipleTemplateResolver extends TemplateResolver {
_multiple: num; _multiple: number;
_cache: Map; _cache: Map<any, any>;
constructor(multiple: num, components: List) { constructor(multiple: number, components: List<Type>) {
super(); super();
this._multiple = multiple; this._multiple = multiple;
this._cache = MapWrapper.create(); this._cache = MapWrapper.create();
@ -149,10 +115,8 @@ class MultipleTemplateResolver extends TemplateResolver {
resolve(component: Type): View { resolve(component: Type): View {
var view = super.resolve(component); var view = super.resolve(component);
var myView = new View({ var myView =
template: MapWrapper.get(this._cache, component), new View({template: MapWrapper.get(this._cache, component), directives: view.directives});
directives: view.directives
});
return myView; return myView;
} }
} }
@ -172,7 +136,8 @@ class MultipleTemplateResolver extends TemplateResolver {
</div> </div>
</div>` </div>`
}) })
class BenchmarkComponentNoBindings {} class BenchmarkComponentNoBindings {
}
@Component() @Component()
@View({ @View({
@ -194,4 +159,5 @@ class BenchmarkComponentNoBindings {}
</div> </div>
</div>` </div>`
}) })
class BenchmarkComponentWithBindings {} class BenchmarkComponentWithBindings {
}

View File

@ -12,20 +12,20 @@ export function main() {
var fixedMatcher; var fixedMatcher;
var fixedSelectorStrings = []; var fixedSelectorStrings = [];
var fixedSelectors = []; var fixedSelectors = [];
for (var i=0; i<count; i++) { for (var i = 0; i < count; i++) {
ListWrapper.push(fixedSelectorStrings, randomSelector()); ListWrapper.push(fixedSelectorStrings, randomSelector());
} }
for (var i=0; i<count; i++) { for (var i = 0; i < count; i++) {
ListWrapper.push(fixedSelectors, CssSelector.parse(fixedSelectorStrings[i])); ListWrapper.push(fixedSelectors, CssSelector.parse(fixedSelectorStrings[i]));
} }
fixedMatcher = new SelectorMatcher(); fixedMatcher = new SelectorMatcher();
for (var i=0; i<count; i++) { for (var i = 0; i < count; i++) {
fixedMatcher.addSelectables(fixedSelectors[i], i); fixedMatcher.addSelectables(fixedSelectors[i], i);
} }
function parse() { function parse() {
var result = []; var result = [];
for (var i=0; i<count; i++) { for (var i = 0; i < count; i++) {
ListWrapper.push(result, CssSelector.parse(fixedSelectorStrings[i])); ListWrapper.push(result, CssSelector.parse(fixedSelectorStrings[i]));
} }
return result; return result;
@ -33,7 +33,7 @@ export function main() {
function addSelectable() { function addSelectable() {
var matcher = new SelectorMatcher(); var matcher = new SelectorMatcher();
for (var i=0; i<count; i++) { for (var i = 0; i < count; i++) {
matcher.addSelectables(fixedSelectors[i], i); matcher.addSelectables(fixedSelectors[i], i);
} }
return matcher; return matcher;
@ -41,10 +41,8 @@ export function main() {
function match() { function match() {
var matchCount = 0; var matchCount = 0;
for (var i=0; i<count; i++) { for (var i = 0; i < count; i++) {
fixedMatcher.match(fixedSelectors[i][0], (selector, selected) => { fixedMatcher.match(fixedSelectors[i][0], (selector, selected) => { matchCount += selected; });
matchCount += selected;
});
} }
return matchCount; return matchCount;
} }
@ -56,16 +54,16 @@ export function main() {
function randomSelector() { function randomSelector() {
var res = randomStr(5); var res = randomStr(5);
for (var i=0; i<3; i++) { for (var i = 0; i < 3; i++) {
res += '.'+randomStr(5); res += '.' + randomStr(5);
} }
for (var i=0; i<3; i++) { for (var i = 0; i < 3; i++) {
res += '['+randomStr(3)+'='+randomStr(6)+']'; res += '[' + randomStr(3) + '=' + randomStr(6) + ']';
} }
return res; return res;
} }
function randomStr(len){ function randomStr(len) {
var s = ''; var s = '';
while (s.length < len) { while (s.length < len) {
s += randomChar(); s += randomChar();
@ -73,11 +71,11 @@ function randomStr(len){
return s; return s;
} }
function randomChar(){ function randomChar() {
var n = randomNum(62); var n = randomNum(62);
if(n<10) return n.toString(); //1-10 if (n < 10) return n.toString(); // 1-10
if(n<36) return StringWrapper.fromCharCode(n+55); //A-Z if (n < 36) return StringWrapper.fromCharCode(n + 55); // A-Z
return StringWrapper.fromCharCode(n+61); //a-z return StringWrapper.fromCharCode(n + 61); // a-z
} }
function randomNum(max) { function randomNum(max) {

View File

@ -1,8 +1,11 @@
import { import {
bootstrap, bootstrap,
Component,
Directive,
DynamicComponentLoader, DynamicComponentLoader,
ElementRef ElementRef,
} from 'angular2/angular2'; View
} from 'angular2/angular2';
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle'; import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
import {List, ListWrapper} from 'angular2/src/facade/collection'; import {List, ListWrapper} from 'angular2/src/facade/collection';
import {reflector} from 'angular2/src/reflection/reflection'; import {reflector} from 'angular2/src/reflection/reflection';
@ -10,11 +13,6 @@ import {ReflectionCapabilities} from 'angular2/src/reflection/reflection_capabil
import {getIntParameter, bindAction} from 'angular2/src/test_lib/benchmark_util'; import {getIntParameter, bindAction} from 'angular2/src/test_lib/benchmark_util';
import {NgIf, NgFor} from 'angular2/directives'; import {NgIf, NgFor} from 'angular2/directives';
// TODO(radokirov): Once the application is transpiled by TS instead of Traceur,
// add those imports back into 'angular2/angular2';
import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations';
import {View} from 'angular2/src/core/annotations_impl/view';
var testList = null; var testList = null;
export function main() { export function main() {
@ -22,9 +20,10 @@ export function main() {
var size = getIntParameter('size'); var size = getIntParameter('size');
testList = ListWrapper.createFixedSize(size); testList = ListWrapper.createFixedSize(size);
bootstrap(AppComponent).then((ref) => { bootstrap(AppComponent)
.then((ref) => {
var injector = ref.injector; var injector = ref.injector;
var app:AppComponent = injector.get(AppComponent); var app: AppComponent = injector.get(AppComponent);
var lifeCycle = injector.get(LifeCycle); var lifeCycle = injector.get(LifeCycle);
bindAction('#reset', function() { bindAction('#reset', function() {
@ -70,33 +69,31 @@ export function main() {
` `
}) })
class AppComponent { class AppComponent {
list:List; list: List;
testingPlainComponents:boolean; testingPlainComponents: boolean;
testingWithDirectives:boolean; testingWithDirectives: boolean;
testingDynamicComponents:boolean; testingDynamicComponents: boolean;
constructor() { constructor() { this.reset(); }
this.reset();
}
reset():void { reset(): void {
this.list = []; this.list = [];
this.testingPlainComponents = false; this.testingPlainComponents = false;
this.testingWithDirectives = false; this.testingWithDirectives = false;
this.testingDynamicComponents = false; this.testingDynamicComponents = false;
} }
createPlainComponents():void { createPlainComponents(): void {
this.list = testList; this.list = testList;
this.testingPlainComponents = true; this.testingPlainComponents = true;
} }
createComponentsWithDirectives():void { createComponentsWithDirectives(): void {
this.list = testList; this.list = testList;
this.testingWithDirectives = true; this.testingWithDirectives = true;
} }
createDynamicComponents():void { createDynamicComponents(): void {
this.list = testList; this.list = testList;
this.testingDynamicComponents = true; this.testingDynamicComponents = true;
} }
@ -104,14 +101,16 @@ class AppComponent {
@Component({selector: 'dummy'}) @Component({selector: 'dummy'})
@View({template: `<div></div>`}) @View({template: `<div></div>`})
class DummyComponent {} class DummyComponent {
}
@Directive({selector: '[dummy-decorator]'}) @Directive({selector: '[dummy-decorator]'})
class DummyDirective {} class DummyDirective {
}
@Component({selector: 'dynamic-dummy'}) @Component({selector: 'dynamic-dummy'})
class DynamicDummy { class DynamicDummy {
constructor(loader:DynamicComponentLoader, location:ElementRef) { constructor(loader: DynamicComponentLoader, location: ElementRef) {
loader.loadIntoExistingLocation(DummyComponent, location); loader.loadIntoExistingLocation(DummyComponent, location);
} }
} }

View File

@ -20,19 +20,13 @@ export function main() {
var D_KEY = Key.get(D); var D_KEY = Key.get(D);
var E_KEY = Key.get(E); var E_KEY = Key.get(E);
var childInjector = injector. var childInjector = injector.resolveAndCreateChild([])
resolveAndCreateChild([]). .resolveAndCreateChild([])
resolveAndCreateChild([]). .resolveAndCreateChild([])
resolveAndCreateChild([]). .resolveAndCreateChild([])
resolveAndCreateChild([]). .resolveAndCreateChild([]);
resolveAndCreateChild([]);
var variousBindings = [ var variousBindings = [A, bind(B).toClass(C), [D, [E]], bind(F).toValue(6)];
A,
bind(B).toClass(C),
[D, [E]],
bind(F).toValue(6)
];
var variousBindingsResolved = Injector.resolve(variousBindings); var variousBindingsResolved = Injector.resolve(variousBindings);
@ -81,72 +75,43 @@ export function main() {
} }
} }
bindAction( bindAction('#getByToken', () => microBenchmark('injectAvg', iterations, getByToken));
'#getByToken', bindAction('#getByKey', () => microBenchmark('injectAvg', iterations, getByKey));
() => microBenchmark('injectAvg', iterations, getByToken) bindAction('#getChild', () => microBenchmark('injectAvg', iterations, getChild));
); bindAction('#instantiate', () => microBenchmark('injectAvg', iterations, instantiate));
bindAction( bindAction('#createVariety', () => microBenchmark('injectAvg', iterations, createVariety));
'#getByKey', bindAction('#createVarietyResolved',
() => microBenchmark('injectAvg', iterations, getByKey) () => microBenchmark('injectAvg', iterations, createVarietyResolved));
);
bindAction(
'#getChild',
() => microBenchmark('injectAvg', iterations, getChild)
);
bindAction(
'#instantiate',
() => microBenchmark('injectAvg', iterations, instantiate)
);
bindAction(
'#createVariety',
() => microBenchmark('injectAvg', iterations, createVariety)
);
bindAction(
'#createVarietyResolved',
() => microBenchmark('injectAvg', iterations, createVarietyResolved)
);
} }
@Injectable() @Injectable()
class A { class A {
constructor() { constructor() { count++; }
count++;
}
} }
@Injectable() @Injectable()
class B { class B {
constructor(a:A) { constructor(a: A) { count++; }
count++;
}
} }
@Injectable() @Injectable()
class C { class C {
constructor(b:B) { constructor(b: B) { count++; }
count++;
}
} }
@Injectable() @Injectable()
class D { class D {
constructor(c:C, b:B) { constructor(c: C, b: B) { count++; }
count++;
}
} }
@Injectable() @Injectable()
class E { class E {
constructor(d:D, c:C) { constructor(d: D, c: C) { count++; }
count++;
}
} }
@Injectable() @Injectable()
class F { class F {
constructor(e:E, d:D) { constructor(e: E, d: D) { count++; }
count++;
}
} }

View File

@ -22,47 +22,35 @@ export function main() {
var proto = ProtoElementInjector.create(null, 0, bindings, false, 0); var proto = ProtoElementInjector.create(null, 0, bindings, false, 0);
var elementInjector = proto.instantiate(null); var elementInjector = proto.instantiate(null);
function instantiate () { function instantiate() {
for (var i = 0; i < iterations; ++i) { for (var i = 0; i < iterations; ++i) {
var ei = proto.instantiate(null); var ei = proto.instantiate(null);
ei.hydrate(appInjector, null, null); ei.hydrate(appInjector, null, null);
} }
} }
function hydrate () { function hydrate() {
for (var i = 0; i < iterations; ++i) { for (var i = 0; i < iterations; ++i) {
elementInjector.dehydrate(); elementInjector.dehydrate();
elementInjector.hydrate(appInjector, null, null); elementInjector.hydrate(appInjector, null, null);
} }
} }
bindAction( bindAction('#instantiate', () => microBenchmark('instantiateAvg', iterations, instantiate));
'#instantiate', bindAction('#hydrate', () => microBenchmark('instantiateAvg', iterations, hydrate));
() => microBenchmark('instantiateAvg', iterations, instantiate)
);
bindAction(
'#hydrate',
() => microBenchmark('instantiateAvg', iterations, hydrate)
);
} }
@Injectable() @Injectable()
class A { class A {
constructor() { constructor() { count++; }
count++;
}
} }
@Injectable() @Injectable()
class B { class B {
constructor() { constructor() { count++; }
count++;
}
} }
@Injectable() @Injectable()
class C { class C {
constructor(a:A, b:B) { constructor(a: A, b: B) { count++; }
count++;
}
} }

View File

@ -1,9 +1,4 @@
import {bootstrap} from 'angular2/angular2'; import {bootstrap, Component, Directive, View} from 'angular2/angular2';
// TODO(radokirov): Once the application is transpiled by TS instead of Traceur,
// add those imports back into 'angular2/angular2';
import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations';
import {View} from 'angular2/src/core/annotations_impl/view';
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle'; import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
@ -11,7 +6,11 @@ import {reflector} from 'angular2/src/reflection/reflection';
import {ReflectionCapabilities} from 'angular2/src/reflection/reflection_capabilities'; import {ReflectionCapabilities} from 'angular2/src/reflection/reflection_capabilities';
import {DOM} from 'angular2/src/dom/dom_adapter'; import {DOM} from 'angular2/src/dom/dom_adapter';
import {window, document, gc} from 'angular2/src/facade/browser'; import {window, document, gc} from 'angular2/src/facade/browser';
import {getIntParameter, getStringParameter, bindAction} from 'angular2/src/test_lib/benchmark_util'; import {
getIntParameter,
getStringParameter,
bindAction
} from 'angular2/src/test_lib/benchmark_util';
import {NgFor, NgSwitch, NgSwitchWhen, NgSwitchDefault} from 'angular2/directives'; import {NgFor, NgSwitch, NgSwitchWhen, NgSwitchDefault} from 'angular2/directives';
import {BrowserDomAdapter} from 'angular2/src/dom/browser_adapter'; import {BrowserDomAdapter} from 'angular2/src/dom/browser_adapter';
@ -27,7 +26,8 @@ export const LARGETABLE_COLS = 'LargetableComponent.cols';
function _createBindings() { function _createBindings() {
return [ return [
bind(BENCHMARK_TYPE).toValue(getStringParameter('benchmarkType')), bind(BENCHMARK_TYPE)
.toValue(getStringParameter('benchmarkType')),
bind(LARGETABLE_ROWS).toValue(getIntParameter('rows')), bind(LARGETABLE_ROWS).toValue(getIntParameter('rows')),
bind(LARGETABLE_COLS).toValue(getIntParameter('columns')) bind(LARGETABLE_COLS).toValue(getIntParameter('columns'))
]; ];
@ -55,8 +55,7 @@ export function main() {
BrowserDomAdapter.makeCurrent(); BrowserDomAdapter.makeCurrent();
var totalRows = getIntParameter('rows'); var totalRows = getIntParameter('rows');
var totalColumns = getIntParameter('columns'); var totalColumns = getIntParameter('columns');
BASELINE_LARGETABLE_TEMPLATE = DOM.createTemplate( BASELINE_LARGETABLE_TEMPLATE = DOM.createTemplate('<table></table>');
'<table></table>');
setupReflector(); setupReflector();
@ -77,7 +76,7 @@ export function main() {
window.console.profile(name + ' w GC'); window.console.profile(name + ' w GC');
var duration = 0; var duration = 0;
var count = 0; var count = 0;
while(count++ < 150) { while (count++ < 150) {
gc(); gc();
var start = window.performance.now(); var start = window.performance.now();
create(); create();
@ -90,7 +89,7 @@ export function main() {
window.console.profile(name + ' w/o GC'); window.console.profile(name + ' w/o GC');
duration = 0; duration = 0;
count = 0; count = 0;
while(count++ < 150) { while (count++ < 150) {
var start = window.performance.now(); var start = window.performance.now();
create(); create();
duration += window.performance.now() - start; duration += window.performance.now() - start;
@ -104,10 +103,10 @@ export function main() {
function ng2CreateDom() { function ng2CreateDom() {
var data = ListWrapper.createFixedSize(totalRows); var data = ListWrapper.createFixedSize(totalRows);
for (var i=0; i<totalRows; i++) { for (var i = 0; i < totalRows; i++) {
data[i] = ListWrapper.createFixedSize(totalColumns); data[i] = ListWrapper.createFixedSize(totalColumns);
for (var j=0; j<totalColumns; j++) { for (var j = 0; j < totalColumns; j++) {
data[i][j] = new CellData(i,j); data[i][j] = new CellData(i, j);
} }
} }
app.data = data; app.data = data;
@ -118,7 +117,8 @@ export function main() {
function noop() {} function noop() {}
function initNg2() { function initNg2() {
bootstrap(AppComponent, _createBindings()).then((ref) => { bootstrap(AppComponent, _createBindings())
.then((ref) => {
var injector = ref.injector; var injector = ref.injector;
app = injector.get(AppComponent); app = injector.get(AppComponent);
lifecycle = injector.get(LifeCycle); lifecycle = injector.get(LifeCycle);
@ -129,16 +129,13 @@ export function main() {
}); });
} }
function baselineDestroyDom() { function baselineDestroyDom() { baselineRootLargetableComponent.update(buildTable(0, 0)); }
baselineRootLargetableComponent.update(buildTable(0, 0));
}
function baselineCreateDom() { function baselineCreateDom() {
baselineRootLargetableComponent.update(buildTable(totalRows, totalColumns)); baselineRootLargetableComponent.update(buildTable(totalRows, totalColumns));
} }
function initBaseline() { function initBaseline() {
baselineRootLargetableComponent = new BaseLineLargetableComponent( baselineRootLargetableComponent = new BaseLineLargetableComponent(
DOM.querySelector(document, 'baseline'), getStringParameter('benchmarkType'), DOM.querySelector(document, 'baseline'), getStringParameter('benchmarkType'),
getIntParameter('rows'), getIntParameter('columns')); getIntParameter('rows'), getIntParameter('columns'));
@ -147,7 +144,8 @@ export function main() {
bindAction('#baselineCreateDom', baselineCreateDom); bindAction('#baselineCreateDom', baselineCreateDom);
bindAction('#baselineUpdateDomProfile', profile(baselineCreateDom, noop, 'baseline-update')); bindAction('#baselineUpdateDomProfile', profile(baselineCreateDom, noop, 'baseline-update'));
bindAction('#baselineCreateDomProfile', profile(baselineCreateDom, baselineDestroyDom, 'baseline-create')); bindAction('#baselineCreateDomProfile',
profile(baselineCreateDom, baselineDestroyDom, 'baseline-create'));
} }
initNg2(); initNg2();
@ -157,7 +155,7 @@ export function main() {
function buildTable(rows, columns) { function buildTable(rows, columns) {
var tbody = DOM.createElement('tbody'); var tbody = DOM.createElement('tbody');
var template = DOM.createElement('span'); var template = DOM.createElement('span');
var i,j,row,cell; var i, j, row, cell;
DOM.appendChild(template, DOM.createElement('span')); DOM.appendChild(template, DOM.createElement('span'));
DOM.appendChild(template, DOM.createTextNode(':')); DOM.appendChild(template, DOM.createTextNode(':'));
DOM.appendChild(template, DOM.createElement('span')); DOM.appendChild(template, DOM.createElement('span'));
@ -180,17 +178,16 @@ function buildTable(rows, columns) {
class BaseLineLargetableComponent { class BaseLineLargetableComponent {
element; element;
table; table;
benchmarkType:string; benchmarkType: string;
rows:number; rows: number;
columns:number; columns: number;
constructor(element,benchmarkType,rows:number,columns:number) { constructor(element, benchmarkType, rows: number, columns: number) {
this.element = element; this.element = element;
this.benchmarkType = benchmarkType; this.benchmarkType = benchmarkType;
this.rows = rows; this.rows = rows;
this.columns = columns; this.columns = columns;
this.table = DOM.clone(BASELINE_LARGETABLE_TEMPLATE.content.firstChild); this.table = DOM.clone(BASELINE_LARGETABLE_TEMPLATE.content.firstChild);
var shadowRoot = DOM.createShadowRoot(this.element) var shadowRoot = DOM.createShadowRoot(this.element) DOM.appendChild(shadowRoot, this.table);
DOM.appendChild(shadowRoot, this.table);
} }
update(tbody) { update(tbody) {
var oldBody = DOM.querySelector(this.table, 'tbody'); var oldBody = DOM.querySelector(this.table, 'tbody');
@ -203,41 +200,29 @@ class BaseLineLargetableComponent {
} }
class CellData { class CellData {
i:number; i: number;
j:number; j: number;
constructor(i,j) { constructor(i, j) {
this.i = i; this.i = i;
this.j = j; this.j = j;
} }
jFn () { jFn() { return this.j; }
return this.j;
}
iFn () { iFn() { return this.i; }
return this.i;
}
} }
@Component({ @Component({selector: 'app'})
selector: 'app'
})
@View({ @View({
directives: [LargetableComponent], directives: [LargetableComponent],
template: `<largetable [data]='data' [benchmarkType]='benchmarkType'></largetable>` template: `<largetable [data]='data' [benchmarkType]='benchmarkType'></largetable>`
}) })
class AppComponent { class AppComponent {
data; data;
benchmarkType:string; benchmarkType: string;
} }
@Component({ @Component({selector: 'largetable', properties: ['data', 'benchmarkType']})
selector: 'largetable',
properties: [
'data',
'benchmarkType'
]
})
@View({ @View({
directives: [NgFor, NgSwitch, NgSwitchWhen, NgSwitchDefault], directives: [NgFor, NgSwitch, NgSwitchWhen, NgSwitchDefault],
template: ` template: `
@ -274,16 +259,13 @@ class AppComponent {
}) })
class LargetableComponent { class LargetableComponent {
data; data;
benchmarkType:string; benchmarkType: string;
rows:number; rows: number;
columns:number; columns: number;
constructor( constructor(@Inject(BENCHMARK_TYPE) benchmarkType: BENCHMARK_TYPE,
@Inject(BENCHMARK_TYPE) benchmarkType, @Inject(LARGETABLE_ROWS) rows: LARGETABLE_ROWS, @Inject(LARGETABLE_COLS) columns) {
@Inject(LARGETABLE_ROWS) rows,
@Inject(LARGETABLE_COLS) columns) {
this.benchmarkType = benchmarkType; this.benchmarkType = benchmarkType;
this.rows = rows; this.rows = rows;
this.columns = columns; this.columns = columns;
} }
} }

View File

@ -1,16 +1,14 @@
import {int, isPresent} from 'angular2/src/facade/lang'; import {isPresent} from 'angular2/src/facade/lang';
import {getIntParameter, bindAction} from 'angular2/src/test_lib/benchmark_util'; import {getIntParameter, bindAction} from 'angular2/src/test_lib/benchmark_util';
import {TimerWrapper} from 'angular2/src/facade/async'; import {TimerWrapper} from 'angular2/src/facade/async';
import {ListWrapper} from 'angular2/src/facade/collection'; import {List, ListWrapper} from 'angular2/src/facade/collection';
import {ScrollAreaComponent} from './scroll_area'; import {ScrollAreaComponent} from './scroll_area';
import {NgIf, NgFor} from 'angular2/directives'; import {NgIf, NgFor} from 'angular2/directives';
import {DOM} from 'angular2/src/dom/dom_adapter'; import {DOM} from 'angular2/src/dom/dom_adapter';
import {document} from 'angular2/src/facade/browser'; import {document} from 'angular2/src/facade/browser';
// TODO(radokirov): Once the application is transpiled by TS instead of Traceur, import {Component, Directive, View} from 'angular2/angular2';
// add those imports back into 'angular2/angular2';
import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations';
import {View} from 'angular2/src/core/annotations_impl/view';
@Component({selector: 'scroll-app'}) @Component({selector: 'scroll-app'})
@View({ @View({
@ -27,9 +25,9 @@ import {View} from 'angular2/src/core/annotations_impl/view';
</div>` </div>`
}) })
export class App { export class App {
scrollAreas:List<int>; scrollAreas: List<int>;
iterationCount:int; iterationCount: int;
scrollIncrement:int; scrollIncrement: int;
constructor() { constructor() {
var appSize = getIntParameter('appSize'); var appSize = getIntParameter('appSize');
@ -40,9 +38,7 @@ export class App {
for (var i = 0; i < appSize; i++) { for (var i = 0; i < appSize; i++) {
ListWrapper.push(this.scrollAreas, i); ListWrapper.push(this.scrollAreas, i);
} }
bindAction('#run-btn', () => { bindAction('#run-btn', () => { this.runBenchmark(); });
this.runBenchmark();
});
bindAction('#reset-btn', () => { bindAction('#reset-btn', () => {
this._getScrollDiv().scrollTop = 0; this._getScrollDiv().scrollTop = 0;
var existingMarker = this._locateFinishedMarker(); var existingMarker = this._locateFinishedMarker();
@ -54,7 +50,7 @@ export class App {
runBenchmark() { runBenchmark() {
var scrollDiv = this._getScrollDiv(); var scrollDiv = this._getScrollDiv();
var n:int = this.iterationCount; var n: int = this.iterationCount;
var scheduleScroll; var scheduleScroll;
scheduleScroll = () => { scheduleScroll = () => {
TimerWrapper.setTimeout(() => { TimerWrapper.setTimeout(() => {
@ -66,7 +62,7 @@ export class App {
this._scheduleFinishedMarker(); this._scheduleFinishedMarker();
} }
}, 0); }, 0);
} };
scheduleScroll(); scheduleScroll();
} }
@ -85,11 +81,7 @@ export class App {
}, 0); }, 0);
} }
_locateFinishedMarker() { _locateFinishedMarker() { return DOM.querySelector(document.body, '#done'); }
return DOM.querySelector(document.body, '#done');
}
_getScrollDiv() { _getScrollDiv() { return DOM.query('body /deep/ #testArea /deep/ #scrollDiv'); }
return DOM.query('body /deep/ #testArea /deep/ #scrollDiv');
}
} }

View File

@ -1,175 +0,0 @@
import {ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
import {Company, Opportunity, Offering, Account, CustomDate, STATUS_LIST}
from './common';
import {NgFor} from 'angular2/directives';
// TODO(radokirov): Once the application is transpiled by TS instead of Traceur,
// add those imports back into 'angular2/angular2';
import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations';
import {View} from 'angular2/src/core/annotations_impl/view';
export class HasStyle {
style:Map;
constructor() {
this.style = MapWrapper.create();
}
set width(w) {
MapWrapper.set(this.style, 'width', w);
}
}
@Component({
selector: 'company-name',
properties: [
'width: cell-width',
'company'
]
})
@View({
directives: [],
template: `<div [style]="style">{{company.name}}</div>`
})
export class CompanyNameComponent extends HasStyle {
company:Company;
}
@Component({
selector: 'opportunity-name',
properties: [
'width: cell-width',
'opportunity'
]
})
@View({
directives: [],
template: `<div [style]="style">{{opportunity.name}}</div>`
})
export class OpportunityNameComponent extends HasStyle {
opportunity:Opportunity;
}
@Component({
selector: 'offering-name',
properties: [
'width: cell-width',
'offering'
]
})
@View({
directives: [],
template: `<div [style]="style">{{offering.name}}</div>`
})
export class OfferingNameComponent extends HasStyle {
offering:Offering;
}
export class Stage {
name:string;
isDisabled:boolean;
style:Map;
apply:Function;
}
@Component({
selector: 'stage-buttons',
properties: [
'width: cell-width',
'offering'
]
})
@View({
directives: [NgFor],
template: `
<div [style]="style">
<button template="ng-for #stage of stages"
[disabled]="stage.isDisabled"
[style]="stage.style"
on-click="setStage(stage)">
{{stage.name}}
</button>
</div>`
})
export class StageButtonsComponent extends HasStyle {
_offering:Offering;
stages:List<Stage>;
get offering():Offering { return this._offering; }
set offering(offering:Offering) {
this._offering = offering;
this._computeStageButtons();
}
setStage(stage:Stage) {
this._offering.status = stage.name;
this._computeStageButtons();
}
_computeStageButtons() {
var disabled = true;
this.stages = ListWrapper.clone(STATUS_LIST
.map((status) => {
var isCurrent = this._offering.status == status;
var stage = new Stage();
stage.name = status;
stage.isDisabled = disabled;
var stageStyle = MapWrapper.create();
MapWrapper.set(stageStyle, 'background-color',
disabled
? '#DDD'
: isCurrent
? '#DDF'
: '#FDD');
stage.style = stageStyle;
if (isCurrent) {
disabled = false;
}
return stage;
}));
}
}
@Component({
selector: 'account-cell',
properties: [
'width: cell-width',
'account'
]
})
@View({
directives: [],
template: `
<div [style]="style">
<a href="/account/{{account.accountId}}">
{{account.accountId}}
</a>
</div>`
})
export class AccountCellComponent extends HasStyle {
account:Account;
}
@Component({
selector: 'formatted-cell',
properties: [
'width: cell-width',
'value'
]
})
@View({
directives: [],
template: `<div [style]="style">{{formattedValue}}</div>`
})
export class FormattedCellComponent extends HasStyle {
formattedValue:string;
set value(value) {
if (value instanceof CustomDate) {
this.formattedValue = `${value.month}/${value.day}/${value.year}`;
} else {
this.formattedValue = value.toString();
}
}
}

View File

@ -0,0 +1,114 @@
import {List, ListWrapper, Map, MapWrapper} from 'angular2/src/facade/collection';
import {Company, Opportunity, Offering, Account, CustomDate, STATUS_LIST} from './common';
import {NgFor} from 'angular2/directives';
import {Component, Directive, View} from 'angular2/angular2';
export class HasStyle {
style: Map<any, any>;
constructor() { this.style = MapWrapper.create(); }
set width(w) { MapWrapper.set(this.style, 'width', w); }
}
@Component({selector: 'company-name', properties: ['width: cell-width', 'company']})
@View({directives: [], template: `<div [style]="style">{{company.name}}</div>`})
export class CompanyNameComponent extends HasStyle {
company: Company;
}
@Component({selector: 'opportunity-name', properties: ['width: cell-width', 'opportunity']})
@View({directives: [], template: `<div [style]="style">{{opportunity.name}}</div>`})
export class OpportunityNameComponent extends HasStyle {
opportunity: Opportunity;
}
@Component({selector: 'offering-name', properties: ['width: cell-width', 'offering']})
@View({directives: [], template: `<div [style]="style">{{offering.name}}</div>`})
export class OfferingNameComponent extends HasStyle {
offering: Offering;
}
export class Stage {
name: string;
isDisabled: boolean;
style: Map;
apply: Function;
}
@Component({selector: 'stage-buttons', properties: ['width: cell-width', 'offering']})
@View({
directives: [NgFor],
template: `
<div [style]="style">
<button template="ng-for #stage of stages"
[disabled]="stage.isDisabled"
[style]="stage.style"
on-click="setStage(stage)">
{{stage.name}}
</button>
</div>`
})
export class StageButtonsComponent extends HasStyle {
_offering: Offering;
stages: List<Stage>;
get offering(): Offering { return this._offering; }
set offering(offering: Offering) {
this._offering = offering;
this._computeStageButtons();
}
setStage(stage: Stage) {
this._offering.status = stage.name;
this._computeStageButtons();
}
_computeStageButtons() {
var disabled = true;
this.stages = ListWrapper.clone(STATUS_LIST.map((status) => {
var isCurrent = this._offering.status == status;
var stage = new Stage();
stage.name = status;
stage.isDisabled = disabled;
var stageStyle = MapWrapper.create();
MapWrapper.set(stageStyle, 'background-color',
disabled ? '#DDD' : isCurrent ? '#DDF' : '#FDD');
stage.style = stageStyle;
if (isCurrent) {
disabled = false;
}
return stage;
}));
}
}
@Component({selector: 'account-cell', properties: ['width: cell-width', 'account']})
@View({
directives: [],
template: `
<div [style]="style">
<a href="/account/{{account.accountId}}">
{{account.accountId}}
</a>
</div>`
})
export class AccountCellComponent extends HasStyle {
account: Account;
}
@Component({selector: 'formatted-cell', properties: ['width: cell-width', 'value']})
@View({directives: [], template: `<div [style]="style">{{formattedValue}}</div>`})
export class FormattedCellComponent extends HasStyle {
formattedValue: string;
set value(value) {
if (value instanceof CustomDate) {
this.formattedValue = `${value.month}/${value.day}/${value.year}`;
} else {
this.formattedValue = value.toString();
}
}
}

View File

@ -1,203 +0,0 @@
import {Math} from 'angular2/src/facade/math';
import {ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
export var ITEMS = 1000;
export var ITEM_HEIGHT = 40;
export var VISIBLE_ITEMS = 17;
export var HEIGHT = ITEMS * ITEM_HEIGHT;
export var VIEW_PORT_HEIGHT = ITEM_HEIGHT * VISIBLE_ITEMS;
export var COMPANY_NAME_WIDTH = 100;
export var OPPORTUNITY_NAME_WIDTH = 100;
export var OFFERING_NAME_WIDTH = 100;
export var ACCOUNT_CELL_WIDTH = 50;
export var BASE_POINTS_WIDTH = 50;
export var KICKER_POINTS_WIDTH = 50;
export var STAGE_BUTTONS_WIDTH = 220;
export var BUNDLES_WIDTH = 120;
export var DUE_DATE_WIDTH = 100;
export var END_DATE_WIDTH = 100;
export var AAT_STATUS_WIDTH = 100;
export var ROW_WIDTH = COMPANY_NAME_WIDTH +
OPPORTUNITY_NAME_WIDTH +
OFFERING_NAME_WIDTH +
ACCOUNT_CELL_WIDTH +
BASE_POINTS_WIDTH +
KICKER_POINTS_WIDTH +
STAGE_BUTTONS_WIDTH +
BUNDLES_WIDTH +
DUE_DATE_WIDTH +
END_DATE_WIDTH +
AAT_STATUS_WIDTH;
export var STATUS_LIST = [
'Planned', 'Pitched', 'Won', 'Lost'
];
export var AAT_STATUS_LIST = [
'Active', 'Passive', 'Abandoned'
];
// Imitate Streamy entities.
// Just a non-trivial object. Nothing fancy or correct.
export class CustomDate {
year:number;
month:number;
day:number;
constructor(y:number, m:number, d:number) {
this.year = y;
this.month = m;
this.day = d;
}
addDays(days:number):CustomDate {
var newDay = this.day + days;
var newMonth = this.month + Math.floor(newDay / 30);
newDay = newDay % 30;
var newYear = this.year + Math.floor(newMonth / 12);
return new CustomDate(newYear, newMonth, newDay);
}
static now():CustomDate {
return new CustomDate(2014, 1, 28);
}
}
export class RawEntity {
_data:Map;
constructor() {
this._data = MapWrapper.create();
}
get(key:string) {
if (key.indexOf('.') == -1) {
return this._data[key];
}
var pieces = key.split('.');
var last = ListWrapper.last(pieces);
pieces.length = pieces.length - 1;
var target = _resolve(pieces, this);
if (target == null) {
return null;
}
return target[last];
}
set(key:string, value) {
if (key.indexOf('.') == -1) {
this._data[key] = value;
return;
}
var pieces = key.split('.');
var last = ListWrapper.last(pieces);
pieces.length = pieces.length - 1;
var target = _resolve(pieces, this);
target[last] = value;
}
remove(key:string) {
if (!key.contains('.')) {
return MapWrapper.delete(this._data, key);
}
var pieces = key.split('.');
var last = ListWrapper.last(pieces);
pieces.length = pieces.length - 1;
var target = _resolve(pieces, this);
return target.remove(last);
}
_resolve(pieces, start) {
var cur = start;
for (var i = 0; i < pieces.length; i++) {
cur = cur[pieces[i]];
if (cur == null) {
return null;
}
}
return cur;
}
}
export class Company extends RawEntity {
get name():string { return this.get('name'); }
set name(val:string) {
this.set('name', val);
}
}
export class Offering extends RawEntity {
get name():string { return this.get('name'); }
set name(val:string) {
this.set('name', val);
}
get company():Company { return this.get('company'); }
set company(val:Company) {
this.set('company', val);
}
get opportunity():Opportunity { return this.get('opportunity'); }
set opportunity(val:Opportunity) {
this.set('opportunity', val);
}
get account():Account { return this.get('account'); }
set account(val:Account) {
this.set('account', val);
}
get basePoints():number { return this.get('basePoints'); }
set basePoints(val:number) {
this.set('basePoints', val);
}
get kickerPoints():number { return this.get('kickerPoints'); }
set kickerPoints(val:number) {
this.set('kickerPoints', val);
}
get status():string { return this.get('status'); }
set status(val:string) {
this.set('status', val);
}
get bundles():string { return this.get('bundles'); }
set bundles(val:string) {
this.set('bundles', val);
}
get dueDate():CustomDate { return this.get('dueDate'); }
set dueDate(val:CustomDate) {
this.set('dueDate', val);
}
get endDate():CustomDate { return this.get('endDate'); }
set endDate(val:CustomDate) {
this.set('endDate', val);
}
get aatStatus():string { return this.get('aatStatus'); }
set aatStatus(val:string) {
this.set('aatStatus', val);
}
}
export class Opportunity extends RawEntity {
get name():string { return this.get('name'); }
set name(val:string) {
this.set('name', val);
}
}
export class Account extends RawEntity {
get accountId():number { return this.get('accountId'); }
set accountId(val:number) {
this.set('accountId', val);
}
}

View File

@ -0,0 +1,159 @@
import {Math} from 'angular2/src/facade/math';
import {ListWrapper, Map, MapWrapper} from 'angular2/src/facade/collection';
export var ITEMS = 1000;
export var ITEM_HEIGHT = 40;
export var VISIBLE_ITEMS = 17;
export var HEIGHT = ITEMS * ITEM_HEIGHT;
export var VIEW_PORT_HEIGHT = ITEM_HEIGHT * VISIBLE_ITEMS;
export var COMPANY_NAME_WIDTH = 100;
export var OPPORTUNITY_NAME_WIDTH = 100;
export var OFFERING_NAME_WIDTH = 100;
export var ACCOUNT_CELL_WIDTH = 50;
export var BASE_POINTS_WIDTH = 50;
export var KICKER_POINTS_WIDTH = 50;
export var STAGE_BUTTONS_WIDTH = 220;
export var BUNDLES_WIDTH = 120;
export var DUE_DATE_WIDTH = 100;
export var END_DATE_WIDTH = 100;
export var AAT_STATUS_WIDTH = 100;
export var ROW_WIDTH = COMPANY_NAME_WIDTH + OPPORTUNITY_NAME_WIDTH + OFFERING_NAME_WIDTH +
ACCOUNT_CELL_WIDTH + BASE_POINTS_WIDTH + KICKER_POINTS_WIDTH +
STAGE_BUTTONS_WIDTH + BUNDLES_WIDTH + DUE_DATE_WIDTH + END_DATE_WIDTH +
AAT_STATUS_WIDTH;
export var STATUS_LIST = ['Planned', 'Pitched', 'Won', 'Lost'];
export var AAT_STATUS_LIST = ['Active', 'Passive', 'Abandoned'];
// Imitate Streamy entities.
// Just a non-trivial object. Nothing fancy or correct.
export class CustomDate {
year: number;
month: number;
day: number;
constructor(y: number, m: number, d: number) {
this.year = y;
this.month = m;
this.day = d;
}
addDays(days: number): CustomDate {
var newDay = this.day + days;
var newMonth = this.month + Math.floor(newDay / 30);
newDay = newDay % 30;
var newYear = this.year + Math.floor(newMonth / 12);
return new CustomDate(newYear, newMonth, newDay);
}
static now(): CustomDate { return new CustomDate(2014, 1, 28); }
}
export class RawEntity {
_data: Map<any, any>;
constructor() { this._data = MapWrapper.create(); }
get(key: string) {
if (key.indexOf('.') == -1) {
return this._data[key];
}
var pieces = key.split('.');
var last = ListWrapper.last(pieces);
pieces.length = pieces.length - 1;
var target = _resolve(pieces, this);
if (target == null) {
return null;
}
return target[last];
}
set(key: string, value) {
if (key.indexOf('.') == -1) {
this._data[key] = value;
return;
}
var pieces = key.split('.');
var last = ListWrapper.last(pieces);
pieces.length = pieces.length - 1;
var target = _resolve(pieces, this);
target[last] = value;
}
remove(key: string) {
if (!key.contains('.')) {
return MapWrapper.delete(this._data, key);
}
var pieces = key.split('.');
var last = ListWrapper.last(pieces);
pieces.length = pieces.length - 1;
var target = _resolve(pieces, this);
return target.remove(last);
}
_resolve(pieces, start) {
var cur = start;
for (var i = 0; i < pieces.length; i++) {
cur = cur[pieces[i]];
if (cur == null) {
return null;
}
}
return cur;
}
}
export class Company extends RawEntity {
get name(): string { return this.get('name'); }
set name(val: string) { this.set('name', val); }
}
export class Offering extends RawEntity {
get name(): string { return this.get('name'); }
set name(val: string) { this.set('name', val); }
get company(): Company { return this.get('company'); }
set company(val: Company) { this.set('company', val); }
get opportunity(): Opportunity { return this.get('opportunity'); }
set opportunity(val: Opportunity) { this.set('opportunity', val); }
get account(): Account { return this.get('account'); }
set account(val: Account) { this.set('account', val); }
get basePoints(): number { return this.get('basePoints'); }
set basePoints(val: number) { this.set('basePoints', val); }
get kickerPoints(): number { return this.get('kickerPoints'); }
set kickerPoints(val: number) { this.set('kickerPoints', val); }
get status(): string { return this.get('status'); }
set status(val: string) { this.set('status', val); }
get bundles(): string { return this.get('bundles'); }
set bundles(val: string) { this.set('bundles', val); }
get dueDate(): CustomDate { return this.get('dueDate'); }
set dueDate(val: CustomDate) { this.set('dueDate', val); }
get endDate(): CustomDate { return this.get('endDate'); }
set endDate(val: CustomDate) { this.set('endDate', val); }
get aatStatus(): string { return this.get('aatStatus'); }
set aatStatus(val: string) { this.set('aatStatus', val); }
}
export class Opportunity extends RawEntity {
get name(): string { return this.get('name'); }
set name(val: string) { this.set('name', val); }
}
export class Account extends RawEntity {
get accountId(): number { return this.get('accountId'); }
set accountId(val: number) { this.set('accountId', val); }
}

View File

@ -14,7 +14,7 @@ export function main() {
bootstrap(App, createBindings()); bootstrap(App, createBindings());
} }
function createBindings():List { function createBindings(): List {
return [bind(APP_VIEW_POOL_CAPACITY).toValue(100000)]; return [bind(APP_VIEW_POOL_CAPACITY).toValue(100000)];
} }
@ -23,16 +23,16 @@ export function setupReflector() {
// TODO(kegluneq): Generate this. // TODO(kegluneq): Generate this.
reflector.registerSetters({ reflector.registerSetters({
'style': (o, m) => { 'style': (o, m) =>
{
// HACK // HACK
MapWrapper.forEach(m, function(v, k) { MapWrapper.forEach(m, function(v, k) { o.style.setProperty(k, v); });
o.style.setProperty(k, v);
});
} }
}); });
reflector.registerMethods({ reflector.registerMethods({
'onScroll': (o, args) => { 'onScroll': (o, args) =>
{
// HACK // HACK
o.onScroll(args[0]); o.onScroll(args[0]);
}, },

View File

@ -1,17 +1,24 @@
import {int, StringWrapper} from 'angular2/src/facade/lang'; import {StringWrapper} from 'angular2/src/facade/lang';
import {List, ListWrapper} from 'angular2/src/facade/collection'; import {List, ListWrapper} from 'angular2/src/facade/collection';
import {CustomDate, Offering, Company, Opportunity, Account, STATUS_LIST, import {
AAT_STATUS_LIST} from './common'; CustomDate,
Offering,
Company,
Opportunity,
Account,
STATUS_LIST,
AAT_STATUS_LIST
} from './common';
export function generateOfferings(count:int):List<Offering> { export function generateOfferings(count: int): List<Offering> {
var res = []; var res = [];
for(var i = 0; i < count; i++) { for (var i = 0; i < count; i++) {
ListWrapper.push(res, generateOffering(i)); ListWrapper.push(res, generateOffering(i));
} }
return res; return res;
} }
export function generateOffering(seed:int):Offering { export function generateOffering(seed: int): Offering {
var res = new Offering(); var res = new Offering();
res.name = generateName(seed++); res.name = generateName(seed++);
res.company = generateCompany(seed++); res.company = generateCompany(seed++);
@ -27,36 +34,47 @@ export function generateOffering(seed:int):Offering {
return res; return res;
} }
export function generateCompany(seed:int):Company { export function generateCompany(seed: int): Company {
var res = new Company(); var res = new Company();
res.name = generateName(seed); res.name = generateName(seed);
return res; return res;
} }
export function generateOpportunity(seed:int):Opportunity { export function generateOpportunity(seed: int): Opportunity {
var res = new Opportunity(); var res = new Opportunity();
res.name = generateName(seed); res.name = generateName(seed);
return res; return res;
} }
export function generateAccount(seed:int):Account { export function generateAccount(seed: int): Account {
var res = new Account(); var res = new Account();
res.accountId = seed; res.accountId = seed;
return res; return res;
} }
var names = [ var names = [
'Foo', 'Bar', 'Baz', 'Qux', 'Quux', 'Garply', 'Waldo', 'Fred', 'Plugh', 'Foo',
'Xyzzy', 'Thud', 'Cruft', 'Stuff' 'Bar',
'Baz',
'Qux',
'Quux',
'Garply',
'Waldo',
'Fred',
'Plugh',
'Xyzzy',
'Thud',
'Cruft',
'Stuff'
]; ];
function generateName(seed:int):string { function generateName(seed: int): string {
return names[seed % names.length]; return names[seed % names.length];
} }
var offsets = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; var offsets = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
function randomDate(seed:int, minDate:CustomDate = null):CustomDate { function randomDate(seed: int, minDate: CustomDate = null): CustomDate {
if (minDate == null) { if (minDate == null) {
minDate = CustomDate.now(); minDate = CustomDate.now();
} }
@ -67,7 +85,7 @@ function randomDate(seed:int, minDate:CustomDate = null):CustomDate {
var stringLengths = [5, 7, 9, 11, 13]; var stringLengths = [5, 7, 9, 11, 13];
var charCodeOffsets = [0, 1, 2, 3, 4, 5, 6, 7, 8]; var charCodeOffsets = [0, 1, 2, 3, 4, 5, 6, 7, 8];
function randomString(seed:int):string { function randomString(seed: int): string {
var len = stringLengths[seed % 5]; var len = stringLengths[seed % 5];
var str = ''; var str = '';
for (var i = 0; i < len; i++) { for (var i = 0; i < len; i++) {

View File

@ -1,13 +1,17 @@
import {ListWrapper, MapWrapper} from 'angular2/src/facade/collection'; import {ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
import {Math} from 'angular2/src/facade/math'; import {Math} from 'angular2/src/facade/math';
// TODO(radokirov): Once the application is transpiled by TS instead of Traceur, import {Component, Directive, View} from 'angular2/angular2';
// add those imports back into 'angular2/angular2';
import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations';
import {View} from 'angular2/src/core/annotations_impl/view';
import {Offering, ITEMS, ITEM_HEIGHT, VISIBLE_ITEMS, VIEW_PORT_HEIGHT, import {
ROW_WIDTH, HEIGHT} from './common'; Offering,
ITEMS,
ITEM_HEIGHT,
VISIBLE_ITEMS,
VIEW_PORT_HEIGHT,
ROW_WIDTH,
HEIGHT
} from './common';
import {generateOfferings} from './random_data'; import {generateOfferings} from './random_data';
import {ScrollItemComponent} from './scroll_item'; import {ScrollItemComponent} from './scroll_item';
import {NgFor} from 'angular2/directives'; import {NgFor} from 'angular2/directives';
@ -33,8 +37,8 @@ import {NgFor} from 'angular2/directives';
</div>` </div>`
}) })
export class ScrollAreaComponent { export class ScrollAreaComponent {
_fullList:List<Offering>; _fullList: List<Offering>;
visibleItems:List<Offering>; visibleItems: List<Offering>;
scrollDivStyle; scrollDivStyle;
paddingDiv; paddingDiv;

View File

@ -1,24 +1,32 @@
import {ListWrapper, MapWrapper} from 'angular2/src/facade/collection'; import {ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
import {CompanyNameComponent, OpportunityNameComponent, import {
OfferingNameComponent, StageButtonsComponent, AccountCellComponent, CompanyNameComponent,
FormattedCellComponent} from './cells'; OpportunityNameComponent,
OfferingNameComponent,
StageButtonsComponent,
AccountCellComponent,
FormattedCellComponent
} from './cells';
// TODO(radokirov): Once the application is transpiled by TS instead of Traceur, import {Component, Directive, View} from 'angular2/angular2';
// add those imports back into 'angular2/angular2';
import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations';
import {View} from 'angular2/src/core/annotations_impl/view';
import {Offering, ITEM_HEIGHT, COMPANY_NAME_WIDTH, OPPORTUNITY_NAME_WIDTH, import {
OFFERING_NAME_WIDTH, ACCOUNT_CELL_WIDTH, BASE_POINTS_WIDTH, Offering,
KICKER_POINTS_WIDTH, STAGE_BUTTONS_WIDTH, BUNDLES_WIDTH, DUE_DATE_WIDTH, ITEM_HEIGHT,
END_DATE_WIDTH, AAT_STATUS_WIDTH} from './common'; COMPANY_NAME_WIDTH,
OPPORTUNITY_NAME_WIDTH,
OFFERING_NAME_WIDTH,
ACCOUNT_CELL_WIDTH,
BASE_POINTS_WIDTH,
KICKER_POINTS_WIDTH,
STAGE_BUTTONS_WIDTH,
BUNDLES_WIDTH,
DUE_DATE_WIDTH,
END_DATE_WIDTH,
AAT_STATUS_WIDTH
} from './common';
@Component({ @Component({selector: 'scroll-item', properties: ['offering']})
selector: 'scroll-item',
properties: [
'offering'
]
})
@View({ @View({
directives: [ directives: [
CompanyNameComponent, CompanyNameComponent,
@ -66,8 +74,7 @@ import {Offering, ITEM_HEIGHT, COMPANY_NAME_WIDTH, OPPORTUNITY_NAME_WIDTH,
</div>` </div>`
}) })
export class ScrollItemComponent { export class ScrollItemComponent {
offering: Offering;
offering:Offering;
itemStyle; itemStyle;
constructor() { constructor() {

View File

@ -1,9 +1,4 @@
import {bootstrap, ViewContainerRef, Compiler} from 'angular2/angular2'; import {bootstrap, Compiler, Component, Directive, View, ViewContainerRef} from 'angular2/angular2';
// TODO(radokirov): Once the application is transpiled by TS instead of Traceur,
// add those imports back into 'angular2/angular2';
import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations';
import {View} from 'angular2/src/core/annotations_impl/view';
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle'; import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
import {reflector} from 'angular2/src/reflection/reflection'; import {reflector} from 'angular2/src/reflection/reflection';
@ -12,17 +7,19 @@ import {DOM} from 'angular2/src/dom/dom_adapter';
import {isPresent} from 'angular2/src/facade/lang'; import {isPresent} from 'angular2/src/facade/lang';
import {List} from 'angular2/src/facade/collection'; import {List} from 'angular2/src/facade/collection';
import {window, document, gc} from 'angular2/src/facade/browser'; import {window, document, gc} from 'angular2/src/facade/browser';
import {getIntParameter, getStringParameter, bindAction} from 'angular2/src/test_lib/benchmark_util'; import {
getIntParameter,
getStringParameter,
bindAction
} from 'angular2/src/test_lib/benchmark_util';
import {NgIf} from 'angular2/directives'; import {NgIf} from 'angular2/directives';
import {BrowserDomAdapter} from 'angular2/src/dom/browser_adapter'; import {BrowserDomAdapter} from 'angular2/src/dom/browser_adapter';
import {APP_VIEW_POOL_CAPACITY} from 'angular2/src/core/compiler/view_pool'; import {APP_VIEW_POOL_CAPACITY} from 'angular2/src/core/compiler/view_pool';
import {bind} from 'angular2/di'; import {bind} from 'angular2/di';
function createBindings():List { function createBindings(): List {
var viewCacheCapacity = getStringParameter('viewcache') == 'true' ? 10000 : 1; var viewCacheCapacity = getStringParameter('viewcache') == 'true' ? 10000 : 1;
return [ return [bind(APP_VIEW_POOL_CAPACITY).toValue(viewCacheCapacity)];
bind(APP_VIEW_POOL_CAPACITY).toValue(viewCacheCapacity)
];
} }
function setupReflector() { function setupReflector() {
@ -40,8 +37,7 @@ export function main() {
BASELINE_TREE_TEMPLATE = DOM.createTemplate( BASELINE_TREE_TEMPLATE = DOM.createTemplate(
'<span>_<template class="ng-binding"></template><template class="ng-binding"></template></span>'); '<span>_<template class="ng-binding"></template><template class="ng-binding"></template></span>');
BASELINE_IF_TEMPLATE = DOM.createTemplate( BASELINE_IF_TEMPLATE = DOM.createTemplate('<span template="if"><tree></tree></span>');
'<span template="if"><tree></tree></span>');
var app; var app;
var lifeCycle; var lifeCycle;
@ -60,7 +56,7 @@ export function main() {
window.console.profile(name + ' w GC'); window.console.profile(name + ' w GC');
var duration = 0; var duration = 0;
var count = 0; var count = 0;
while(count++ < 150) { while (count++ < 150) {
gc(); gc();
var start = window.performance.now(); var start = window.performance.now();
create(); create();
@ -73,7 +69,7 @@ export function main() {
window.console.profile(name + ' w/o GC'); window.console.profile(name + ' w/o GC');
duration = 0; duration = 0;
count = 0; count = 0;
while(count++ < 150) { while (count++ < 150) {
var start = window.performance.now(); var start = window.performance.now();
create(); create();
duration += window.performance.now() - start; duration += window.performance.now() - start;
@ -85,8 +81,7 @@ export function main() {
} }
function ng2CreateDom() { function ng2CreateDom() {
var values = count++ % 2 == 0 ? var values = count++ % 2 == 0 ? ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*'] :
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*'] :
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', '-']; ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', '-'];
app.initData = buildTree(maxDepth, values, 0); app.initData = buildTree(maxDepth, values, 0);
@ -96,7 +91,8 @@ export function main() {
function noop() {} function noop() {}
function initNg2() { function initNg2() {
bootstrap(AppComponent, createBindings()).then((ref) => { bootstrap(AppComponent, createBindings())
.then((ref) => {
var injector = ref.injector; var injector = ref.injector;
lifeCycle = injector.get(LifeCycle); lifeCycle = injector.get(LifeCycle);
@ -108,13 +104,10 @@ export function main() {
}); });
} }
function baselineDestroyDom() { function baselineDestroyDom() { baselineRootTreeComponent.update(new TreeNode('', null, null)); }
baselineRootTreeComponent.update(new TreeNode('', null, null));
}
function baselineCreateDom() { function baselineCreateDom() {
var values = count++ % 2 == 0 ? var values = count++ % 2 == 0 ? ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*'] :
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*'] :
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', '-']; ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', '-'];
baselineRootTreeComponent.update(buildTree(maxDepth, values, 0)); baselineRootTreeComponent.update(buildTree(maxDepth, values, 0));
@ -129,7 +122,8 @@ export function main() {
bindAction('#baselineCreateDom', baselineCreateDom); bindAction('#baselineCreateDom', baselineCreateDom);
bindAction('#baselineUpdateDomProfile', profile(baselineCreateDom, noop, 'baseline-update')); bindAction('#baselineUpdateDomProfile', profile(baselineCreateDom, noop, 'baseline-update'));
bindAction('#baselineCreateDomProfile', profile(baselineCreateDom, baselineDestroyDom, 'baseline-create')); bindAction('#baselineCreateDomProfile',
profile(baselineCreateDom, baselineDestroyDom, 'baseline-create'));
} }
initNg2(); initNg2();
@ -137,9 +131,9 @@ export function main() {
} }
class TreeNode { class TreeNode {
value:string; value: string;
left:TreeNode; left: TreeNode;
right:TreeNode; right: TreeNode;
constructor(value, left, right) { constructor(value, left, right) {
this.value = value; this.value = value;
this.left = left; this.left = left;
@ -149,19 +143,17 @@ class TreeNode {
function buildTree(maxDepth, values, curDepth) { function buildTree(maxDepth, values, curDepth) {
if (maxDepth === curDepth) return new TreeNode('', null, null); if (maxDepth === curDepth) return new TreeNode('', null, null);
return new TreeNode( return new TreeNode(values[curDepth], buildTree(maxDepth, values, curDepth + 1),
values[curDepth], buildTree(maxDepth, values, curDepth + 1));
buildTree(maxDepth, values, curDepth+1),
buildTree(maxDepth, values, curDepth+1));
} }
// http://jsperf.com/nextsibling-vs-childnodes // http://jsperf.com/nextsibling-vs-childnodes
class BaseLineTreeComponent { class BaseLineTreeComponent {
element; element;
value:BaseLineInterpolation; value: BaseLineInterpolation;
left:BaseLineIf; left: BaseLineIf;
right:BaseLineIf; right: BaseLineIf;
constructor(element) { constructor(element) {
this.element = element; this.element = element;
var clone = DOM.clone(BASELINE_TREE_TEMPLATE.content.firstChild); var clone = DOM.clone(BASELINE_TREE_TEMPLATE.content.firstChild);
@ -175,7 +167,7 @@ class BaseLineTreeComponent {
child = DOM.nextSibling(child); child = DOM.nextSibling(child);
this.right = new BaseLineIf(child); this.right = new BaseLineIf(child);
} }
update(value:TreeNode) { update(value: TreeNode) {
this.value.update(value.value); this.value.update(value.value);
this.left.update(value.left); this.left.update(value.left);
this.right.update(value.right); this.right.update(value.right);
@ -183,13 +175,13 @@ class BaseLineTreeComponent {
} }
class BaseLineInterpolation { class BaseLineInterpolation {
value:string; value: string;
textNode; textNode;
constructor(textNode) { constructor(textNode) {
this.value = null; this.value = null;
this.textNode = textNode; this.textNode = textNode;
} }
update(value:string) { update(value: string) {
if (this.value !== value) { if (this.value !== value) {
this.value = value; this.value = value;
DOM.setText(this.textNode, value + ' '); DOM.setText(this.textNode, value + ' ');
@ -198,15 +190,15 @@ class BaseLineInterpolation {
} }
class BaseLineIf { class BaseLineIf {
condition:boolean; condition: boolean;
component:BaseLineTreeComponent; component: BaseLineTreeComponent;
anchor; anchor;
constructor(anchor) { constructor(anchor) {
this.anchor = anchor; this.anchor = anchor;
this.condition = false; this.condition = false;
this.component = null; this.component = null;
} }
update(value:TreeNode) { update(value: TreeNode) {
var newCondition = isPresent(value); var newCondition = isPresent(value);
if (this.condition !== newCondition) { if (this.condition !== newCondition) {
this.condition = newCondition; this.condition = newCondition;
@ -227,12 +219,9 @@ class BaseLineIf {
} }
@Component({selector: 'app'}) @Component({selector: 'app'})
@View({ @View({directives: [TreeComponent], template: `<tree [data]='initData'></tree>`})
directives: [TreeComponent],
template: `<tree [data]='initData'></tree>`
})
class AppComponent { class AppComponent {
initData:TreeNode; initData: TreeNode;
constructor() { constructor() {
// TODO: We need an initial value as otherwise the getter for data.value will fail // TODO: We need an initial value as otherwise the getter for data.value will fail
// --> this should be already caught in change detection! // --> this should be already caught in change detection!
@ -240,15 +229,12 @@ class AppComponent {
} }
} }
@Component({ @Component({selector: 'tree', properties: ['data']})
selector: 'tree',
properties: ['data']
})
@View({ @View({
directives: [TreeComponent, NgIf], directives: [TreeComponent, NgIf],
template: `<span> {{data.value}} <span template='ng-if data.right != null'><tree [data]='data.right'></tree></span><span template='ng-if data.left != null'><tree [data]='data.left'></tree></span></span>` template:
`<span> {{data.value}} <span template='ng-if data.right != null'><tree [data]='data.right'></tree></span><span template='ng-if data.left != null'><tree [data]='data.left'></tree></span></span>`
}) })
class TreeComponent { class TreeComponent {
data:TreeNode; data: TreeNode;
} }