Angular 2 change detection through event emitter consumes tremendous CPU time

I noticed that my Angular 2 application is getting a little slow after use.

I profiled the processor time and found out that there are massive change detection checks.

Processor profile immediately after page loading ...

Processor profile after page load

... compared to the CPU profile after using the page for a while.

CPU profile after using page for a while

I used a lot of EventEmitter in different services to communicate between many components.

After testing for some time, it seems that the emitter for the window scroll event causes most of the large load.

Profile of the processor after using the page for some time without highlighting scroll events:

Processor profile without highlighting scroll events

Here is the service implementation:

 @Injectable() export class WindowService { @Output() scrolled$: EventEmitter<WindowScrolled> = new EventEmitter(); private scrollDebounceTime = 25; constructor() { this.addEvent(window, 'scroll', this.debounce((event) => { this.scrolled$.emit(new WindowScrolled(window.scrollX, window.scrollY)); }, this.scrollDebounceTime)); } // ... other functions } 

Questions

  • How can I debug change detection calls to see where they apply?
  • What else can cause so many change detection calls?
  • If I use EventEmitter , how to use it correctly?

Change 1

In addition, I place the grid tree component because the changes can be caused by the recursive tree structure that my components build.

 @Component({ selector: 'hierarchy-grid-tree', moduleId: __moduleName, // use `__moduleName` from System.js for relative styleUrls and templateUrls styleUrls : [`hierarchy-grid.css`], template: `<div class="flex-container"> <div class="flex-item" *ngFor="#node of nodes; #i = index" [ngClass]="{'intermediate': node.has()}" [ngStyle]="{'flex-grow': flexGrow(node), 'flex-basis': visRepConf.nodeWidth+'px', 'order': (i+1)}"> <hierarchy-node [node]="node" [visRepConf]="visRepConf" #hnInstance></hierarchy-node> <hierarchy-grid-tree [nodes]="node.children()" [visRepConf]="visRepConf" [show-depth]="showDepth" [curr-depth]="currDepth + 1" *ngIf="(showDepth === -1 || currDepth < depth) && node.has() && !hnInstance.isCollapsed"></hierarchy-grid-tree> </div> </div>`, providers: [], directives: [HierarchyGridTreeComponent, HierarchyNodeComponent] }) export class HierarchyGridTreeComponent { @Input() nodes: Array<Node> = []; @Input() visRepConf:VisRepresentationConfig; @Input('show-depth') showDepth = -1; @Input('curr-depth') currDepth = 1; constructor() { } flexGrow(node) { if(node.has()) { return node.numChildrenRecursive(); } return 'auto'; } } // see html demo at http://codepen.io/anon/pen/pgqjPP @Component({ selector: 'hierarchy-grid', moduleId: __moduleName, // use `__moduleName` from System.js for relative styleUrls and templateUrls styleUrls : [`hierarchy-grid.css`], template: `<div class="color-{{color}}" [ngClass]="{'selects-infra':selectsInfra}" (click)="selectInfra($event)"> <p *ngIf="showInfraTitle" class="title">{{title}}</p> <hierarchy-node *ngIf="external" [node]="external" [visRepConf]="visRepConf"></hierarchy-node> <hierarchy-grid-tree [nodes]="nodes" [visRepConf]="visRepConf"></hierarchy-grid-tree> </div>`, providers: [], directives: [HierarchyGridTreeComponent, HierarchyNodeComponent] }) export class HierarchyGridComponent implements OnInit, OnChanges { @Input('vis-config') visConfig:string = ''; @Input('infra') infra:Infrastructure; @Input('show-external') showExternal:boolean = false; @Input('show-infra-title') showInfraTitle:boolean = false; @Input('selects-infra') selectsInfra:boolean = false; private visRepConf:VisRepresentationConfig; private external:ExternalNode; private nodes:Array<Node>; private color:string; private title:string; constructor(private nodeSelection:NodeSelectionService) { } ngOnChanges(changes) { if(changes.infra !== undefined && this.infra !== undefined) { this.visRepConf = this.infra.visConfig.get(this.visConfig); this.nodes = [this.infra.root]; if(this.showExternal) { this.external = this.infra.external; } this.color = this.infra.color; this.title = this.infra.name; } } selectInfra($event) { if(this.selectsInfra) { this.nodeSelection.infra = this.infra; } } } 

The resulting hierarchical grid:

Hierarchical grid

+6
source share

All Articles