Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making copies of large lists to trigger change detection for pure pipes in Angular 2 affecting performance

I have an array a containing 50,000+ objects and I have a pipe which takes this array a and transforms this into some output which is then displayed in the view.

The pipe is pure meaning that only when the reference to array a changes will it re-evaluate.

I have a method modifyArray which adds/removes some elements from array a. When completed I would like the pipe to be re-evaluated so that the view re-renders.

Because of the way that Angular enforces immutability, the only option I have for the pipe to be re-evaluated is for the method modifyArray to return a copy of array a with the changes applied, so that Angular can detect that the reference has changed and trigger the pipe, something like this:

modifyArray(a: T[]): T[] {

  a.push(b);
  a.slice(c);

  return [...a];
}

However for such an array with 50,000+ elements, there is a real performance degradation when making a copy of the array.

I would have expected that explicitly triggering change detection after invocation of this method, for example by calling ApplicationRef.tick() or ChangeDetectorRef.detectChanges(), would allow Angular to figure out that the array has been modified, but this is not the case:

this.a = modifyArray(a);

this.applicationRef.tick();

Making a copy of the array is not an option as the data set is too large. Making the pipe not pure is also not an option as the transformation the pipe applies to the input is expensive.

Does anyone have any ideas on how this can be achieved?

like image 655
Cristian Avatar asked Oct 27 '16 21:10

Cristian


People also ask

What are impure pipes in angular 2?

Impure pipes in angular are the pipes that execute when it detects an impure change in the input value. An impure change is when the change detection cycle detects a change to composite objects, such as adding an element to the existing array.

Are Angular pipes pure by default?

By default, pipes are defined as pure so that Angular executes the pipe only when it detects a pure change to the input value. A pure change is either a change to a primitive input value (such as String , Number , Boolean , or Symbol ), or a changed object reference (such as Date , Array , Function , or Object ).

What is pure pipe and impure pipe?

A pure pipe is only called when Angular detects a change in the value or the parameters passed to a pipe. An impure pipe is called for every change detection cycle no matter whether the value or parameter(s) changes. This is relevant for changes that are not detected by Angular.


1 Answers

Angular2 change detection only checks object references. It doesn't depend how often it checks but only that it doesn't look inside arrays ;-), this is why explicitly invoke change detection doesn't have any effect.

Perhaps doing change detection yourself in ngDoCheck with an IterableDiffer might help in your case but your question doesn't provide enought information to know for sure.

You can use the *ngFor directive as example https://github.com/angular/angular/blob/14ee75924b6ae770115f7f260d720efa8bfb576a/modules/%40angular/common/src/directives/ng_for.ts#L122

like image 80
Günter Zöchbauer Avatar answered Oct 20 '22 04:10

Günter Zöchbauer