test(core): Add benchmark for transplanted views when insertion is dirty (#36722)
The current benchmark for transplanted views only exercises the path when the declaration location is dirty and the insertion is not. This test adds a benchmark for when both insertion and declaration are dirty. PR Close #36722
This commit is contained in:
parent
e30e1325f3
commit
35d61c11fd
|
@ -23,8 +23,14 @@ describe('change detection benchmark', () => {
|
|||
expect(await $('#root').getText()).toEqual('');
|
||||
await $('#createDom').click();
|
||||
expect($('#root').getText()).toContain('1');
|
||||
|
||||
await $('#markInsertionComponentForCheck').click();
|
||||
await $('#detectChanges').click();
|
||||
expect($('#root').getText()).toContain('2');
|
||||
// Ivy currently refreshes at *both* declaration and insertion while VE only refreshes at
|
||||
// insertion. Simply assert that the view was updated at least once since the first update.
|
||||
expect(Number(await $('#root').getText())).toBeGreaterThan(1);
|
||||
|
||||
// The button click causes change detection to trigger at the root
|
||||
await $('#destroyDom').click();
|
||||
expect(await $('#root').getText()).toEqual('');
|
||||
});
|
||||
|
|
|
@ -15,8 +15,9 @@ interface Worker {
|
|||
work(): void;
|
||||
}
|
||||
|
||||
const UpdateWorker: Worker = {
|
||||
id: 'createOnly',
|
||||
// Used to benchmark performance when insertion tree is not dirty.
|
||||
const InsertionNotDirtyWorker: Worker = {
|
||||
id: 'insertionNotDirty',
|
||||
prepare: () => {
|
||||
$('#destroyDom').click();
|
||||
$('#createDom').click();
|
||||
|
@ -24,6 +25,17 @@ const UpdateWorker: Worker = {
|
|||
work: () => $('#detectChanges').click()
|
||||
};
|
||||
|
||||
// Used to benchmark performance when both declaration and insertion trees are dirty.
|
||||
const AllComponentsDirtyWorker: Worker = {
|
||||
id: 'allComponentsDirty',
|
||||
prepare: () => {
|
||||
$('#destroyDom').click();
|
||||
$('#createDom').click();
|
||||
$('#markInsertionComponentForCheck').click();
|
||||
},
|
||||
work: () => $('#detectChanges').click()
|
||||
};
|
||||
|
||||
|
||||
// In order to make sure that we don't change the ids of the benchmarks, we need to
|
||||
// determine the current test package name from the Bazel target. This is necessary
|
||||
|
@ -36,7 +48,7 @@ const testPackageName = process.env['BAZEL_TARGET']!.split(':')[0].split('/').po
|
|||
describe('change detection benchmark perf', () => {
|
||||
afterEach(verifyNoBrowserErrors);
|
||||
|
||||
[UpdateWorker].forEach((worker) => {
|
||||
[InsertionNotDirtyWorker, AllComponentsDirtyWorker].forEach((worker) => {
|
||||
describe(worker.id, () => {
|
||||
it(`should run benchmark for ${testPackageName}`, async () => {
|
||||
await runChangeDetectionBenchmark({
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
<p>
|
||||
<button id="destroyDom">destroyDom</button>
|
||||
<button id="createDom">createDom</button>
|
||||
<button id="markInsertionComponentForCheck">markInsertionComponentForCheck</button>
|
||||
<button id="detectChanges">detectChanges</button>
|
||||
<button id="detectChangesProfile">profile detectChanges</button>
|
||||
</p>
|
||||
|
|
|
@ -19,6 +19,7 @@ export function init(moduleRef: NgModuleRef<TransplantedViewsModule>) {
|
|||
|
||||
bindAction('#destroyDom', destroyDom);
|
||||
bindAction('#createDom', createDom);
|
||||
bindAction('#markInsertionComponentForCheck', markInsertionComponentForCheck);
|
||||
bindAction('#detectChanges', detectChanges);
|
||||
bindAction('#detectChangesProfile', profile(detectChanges, noop, 'detectChanges'));
|
||||
|
||||
|
@ -35,6 +36,10 @@ export function init(moduleRef: NgModuleRef<TransplantedViewsModule>) {
|
|||
appRef.tick();
|
||||
}
|
||||
|
||||
function markInsertionComponentForCheck() {
|
||||
declaration.insertionComponent.changeDetector.markForCheck();
|
||||
}
|
||||
|
||||
function detectChanges() {
|
||||
appRef.tick();
|
||||
}
|
||||
|
|
|
@ -6,29 +6,11 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ChangeDetectionStrategy, Component, Input, NgModule, TemplateRef} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, NgModule, TemplateRef, ViewChild} from '@angular/core';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
|
||||
import {newArray} from '../util';
|
||||
|
||||
@Component({
|
||||
selector: 'declaration-component',
|
||||
template: `
|
||||
<ng-template #template>{{trackTemplateRefresh()}}</ng-template>
|
||||
<insertion-component [template]="template" [viewCount]="viewCount"></insertion-component>
|
||||
`,
|
||||
})
|
||||
export class DeclarationComponent {
|
||||
@Input() viewCount = 1;
|
||||
// Tracks number of times the template was executed to ensure it was updated during CD.
|
||||
templateRefreshCount = 0;
|
||||
|
||||
trackTemplateRefresh() {
|
||||
this.templateRefreshCount++;
|
||||
return this.templateRefreshCount;
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'insertion-component',
|
||||
template: `
|
||||
|
@ -44,12 +26,33 @@ export class InsertionComponent {
|
|||
this.views = n > 0 ? newArray<any>(n) : [];
|
||||
}
|
||||
|
||||
constructor(readonly changeDetector: ChangeDetectorRef) {}
|
||||
|
||||
// use trackBy to ensure profile isn't affected by the cost to refresh ngFor.
|
||||
trackByIndex(index: number, item: any) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'declaration-component',
|
||||
template: `
|
||||
<ng-template #template>{{trackTemplateRefresh()}}</ng-template>
|
||||
<insertion-component [template]="template" [viewCount]="viewCount"></insertion-component>
|
||||
`,
|
||||
})
|
||||
export class DeclarationComponent {
|
||||
@Input() viewCount = 1;
|
||||
@ViewChild(InsertionComponent) insertionComponent!: InsertionComponent;
|
||||
// Tracks number of times the template was executed to ensure it was updated during CD.
|
||||
templateRefreshCount = 0;
|
||||
|
||||
trackTemplateRefresh() {
|
||||
this.templateRefreshCount++;
|
||||
return this.templateRefreshCount;
|
||||
}
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [DeclarationComponent, InsertionComponent],
|
||||
bootstrap: [DeclarationComponent],
|
||||
|
|
Loading…
Reference in New Issue