mgechev/angular-performance-checklist

Inaccurate trackBy section

mgechev opened this issue · 7 comments

Looking at the DefaultIterableDiffer, it uses trackByIdentity function in case the trackBy argument is not provided. This makes the trackBy section inaccurate since Angular is never going to destroy the entire list in case trackBy is not provided to the differ.

This change might has been introduced in recent releases.

@tytskyi would you verify so that we can correct the content?

Hi @mgechev i will look into this on weekend.

Hi @mgechev i confirm that it does not destroy the whole list.

Further investigation gives me next results:
You are right it does track by identity by default.

  1. No track-by provided - Developer updates item of collection inplace:
    -- No dom nodes are removed. Content of target node is changed.

  2. No track-by provided - Developer changes item by creating new object of the same type (breaking reference), other items remains the same:
    -- Target dom node is removed and new node is created and inserted on its place.

  3. Track-by provided - Developer changes item by creating new object of the same type (breaking reference), other items remains the same:
    -- No dom nodes are removed. Content of target node is changed.

Which means that wording is too dramatic and must be changed from statement that the whole list is re-rendered - to something like "giving the hint to Angular how to identify items". And the bigger performance win is achieved when reloading big list of search results from server - when track-by provided dom nodes would be re-used for matching items.

@tytskyi your suggestion sounds good. Would you want to update this section?

@mgechev

Let's consider this a draft. I think the structure is ok, however i am not sure in language - i will need to refine it tomorrow, plus i am open for suggestions:


Use trackBy option for *ngFor directive

The *ngFor directive is used for rendering a collection. By default *ngFor identifies object uniqueness by reference.

Which means when developer breaks reference to object during updating item's content Angular treats it as removal of the old object and addition of the new object. This effects in destroying old DOM node in the list and adding new DOM node on its place.

Developer can provide a hint for angular how to identify object uniqueness: custom tracking function as trackBy option for the *ngFor directive. Tracking function takes two arguments: index and item. Angular uses the value returned from tracking function to track items identity. It is very common to use ID of the particular record as the unique key.

Even bigger performance save would be if trackBy is implemented for some collection which can be reloaded from the server (for example search results). Where each fetch will return collection of freshly new objects.

Example

@Component({
  selector: 'yt-feed',
  template: `
  <h1>Your video feed</h1>
  <yt-player *ngFor="let video of feed; trackBy: trackById" [video]="video"></yt-player>
`
})
export class YtFeedComponent {
  feed = [
    {
      id: 3849, // note "id" field, we refer to it in "trackById" function
      title: "Angular in 60 minutes",
      url: "http://youtube.com/ng2-in-60-min",
      likes: "29345"
    },
    // ...
  ];

  trackById(index, item) {
    return item.id;
  }
}

@tytskyi I like it, maybe we can drop:

Even bigger performance save would be if trackBy is implemented for some collection which can be reloaded from the server (for example search results). Where each fetch will return collection of freshly new objects.

@mgechev yes i am happy to drop it, plus i want to fix definite article

custom tracking function as the trackBy option`

If you are happy with this patch i will send PR in 1 hour

Sounds good to me!