He who thinks change detection is depth-first and he who thinks it’s breadth-first are both usually right

Post Editor

Do you know if Angular first checks siblings of the current component (breadth-first) or its children (depth-first)? This article demonstrates that the answer depends on what operations of change detection you consider.

3 min read
0 comments
post

He who thinks change detection is depth-first and he who thinks it’s breadth-first are both usually right

Do you know if Angular first checks siblings of the current component (breadth-first) or its children (depth-first)? This article demonstrates that the answer depends on what operations of change detection you consider.

post
post
3 min read
0 comments
0 comments

I was once asked if change detection in Angular is depth or breadth first. This basically means whether Angular first checks siblings of the current component (breadth-first) or its children (depth-first). I hadn’t given any prior thought to this question so I just went with my gut and the knowledge of internals. I declared that it was depth-first. Later, to check my assertion, I created a tree of components and put some logging logic inside the ngDoCheck hook:

<>Copy
@Component({ selector: 'r-comp', template: `{{addRender()}}` }) export class RComponent { ngDoCheck() { // holds all calls in order and is logged to console calls.ngDoCheck.push('R'); }

And to my surprise, it turned out that some siblings were checked first as depicted on the diagram below:

So here you see that Angular checks K and then V, L and then C and so on. So was I wrong and it’s really a breadth-first algorithm? Well, not exactly. First thing to notice in the above representation is that it’s not a proper breadth-first algorithm. The conventional implementation of the algorithm checks all siblings on the same level, whereas in the diagram above as you can see the algorithm indeed checks L and C sibling components, but instead of checking X and F it goes down to J and O. Also, the implementation of the breadth-first graph traversal algorithm is well defined but I couldn’t find it in the sources. So I decided to run another experiment and put a logging logic in a custom function called when change detection evaluates expressions:

<>Copy
@Component({ selector: 'r-comp', template: `{{addRender()}}` }) export class RComponent { addRender() { calls.render.push('R'); } }

And this time I got different results:

It’s a proper depth-first graph traversal algorithm. So what’s going on here? It’s actually pretty simple, let me explain.

Change detection operations
Link to this section

To understand the difference in behavior we need to take a look at the operations performed by change detection mechanism when checking a component. If you’ve read my other articles on change detection you probably know that the key operations performed by change detection are the following:

  • update child components properties
  • call NgOnChanges and NgDoCheck lifecycle hooks on child components
  • update DOM on the current component
  • run change detection for child components

I highlighted one interesting specifics above — when Angular checks the current component it calls lifecycle hooks on child components, but renders DOM for the current component. And that’s a very important distinction. This is precisely the reason that makes it seem as if the algorithm runs breadth-first if we put logging into NgDoCheck hook. When Angular checks a current component it calls lifecycle hooks for all its child components which are siblings. Suppose Angular checks K component now and calls NgDoCheck lifecycle hook on L and C. So, we get the following:

Looks like breadth-first algorithm. However, remember that Angular still in the process of checking K component. So after completing all operations for the K component it doesn’t proceed to checking the sibling V component, as it would with the breadth-first implementation. Instead, it goes on to check L component, which is a child of K. This is the depth-first implementation of change detection algorithm. And as we now know it will call ngDoCheck on J and O components and this is exactly what happens:

So, after all, my gut didn’t let me down. Change detection mechanism is implemented as depth-first internally, but involves calling ngDoCheck lifecycle hooks on sibling components first. By the way, I already described this logic in depth in the If you think `ngDoCheck` means your component is being checked — read this article.

Stackblitz demo
Link to this section

Here you can see the demo with logging logic in different places.

Comments (0)

Be the first to leave a comment

Share

About the author

author_image

Max is a self-taught software engineer that believes in fundamental knowledge and hardcore learning. He’s the founder of inDepth.dev community and one of the top users on StackOverflow (70k rep).

author_image

About the author

Max Koretskyi

Max is a self-taught software engineer that believes in fundamental knowledge and hardcore learning. He’s the founder of inDepth.dev community and one of the top users on StackOverflow (70k rep).

About the author

author_image

Max is a self-taught software engineer that believes in fundamental knowledge and hardcore learning. He’s the founder of inDepth.dev community and one of the top users on StackOverflow (70k rep).

Looking for a JS job?
Job logo
PDQ team| Senior JavaScript developer (Angular/Node)

SD Solutions

Ukraine
Remote
$60k - $80k
Job logo
Senior Full-Stack Developer (Node+Angular)

A-Listware

Ukraine
Remote
$48k - $78k
Job logo
Senior Full stack (Angular+Node)

Monolith

Ukraine
Remote
$60k - $84k
Job logo
AngularJS Developer/.net Core - Remote Contract

InfoMagnus

United States
Remote
$115k - $134k
More jobs
NxAngularCli
NxAngularCli
NxAngularCli

Featured articles

Angularpost
13 September 20218 min read
Tracking user interaction area

Explore one of the most complex pieces of Taiga UI — ActiveZone directive that keeps an eye on what region user is working with. It touches on low-level native DOM events API, advanced RxJS and Dependency Injection, ShadowDOM and more!

Angularpost
13 September 20218 min read
Tracking user interaction area

Explore one of the most complex pieces of Taiga UI — ActiveZone directive that keeps an eye on what region user is working with. It touches on low-level native DOM events API, advanced RxJS and Dependency Injection, ShadowDOM and more!

Read more
AngularpostTracking user interaction area

13 September 2021

8 min read

Explore one of the most complex pieces of Taiga UI — ActiveZone directive that keeps an eye on what region user is working with. It touches on low-level native DOM events API, advanced RxJS and Dependency Injection, ShadowDOM and more!

Read more
Angularpost
7 September 202122 min read
Designing Angular architecture - Container-Presentation pattern

Designing architecture could be tricky, especially in the agile world, where requirement changes are frequent. So your design has to support that and provides extendibility without the need for serious modification. In such cases, you will find the Container-Presentation pattern instrumental.

micro frontendspost
6 September 202125 min read
Taking micro-frontends to the next level

The micro-frontends concept has been out there for quite a while. We’ve been using this architecture in Wix since around 2013, long before it was even given this name. In this article I’d like to share some of the things we did in order to evolve the concept of developing big scale micro-frontends.

micro frontendspost
6 September 202125 min read
Taking micro-frontends to the next level

The micro-frontends concept has been out there for quite a while. We’ve been using this architecture in Wix since around 2013, long before it was even given this name. In this article I’d like to share some of the things we did in order to evolve the concept of developing big scale micro-frontends.

Read more
micro frontendspostTaking micro-frontends to the next level

6 September 2021

25 min read

The micro-frontends concept has been out there for quite a while. We’ve been using this architecture in Wix since around 2013, long before it was even given this name. In this article I’d like to share some of the things we did in order to evolve the concept of developing big scale micro-frontends.

Read more