Q: How does angular resolve infinite recursion? I am following this Udemy course:
https://www.udemy.com/the-complete-guide-to-angular-2/
I'm on part 2.13 on String Interpolation.
As part of the lesson, you define a simple function in your component to display one of the properties of your class:
export class ServerComponent{
    serverId = 10;
    serverStatus = 'offline';

    getServerStatus(){
        return this.serverStatus;
    }
}

Then in your component HTML, you bind that function to the template:
<P>Server with ID {{ serverId }} is {{ getServerStatus() }}</P>

What I wanted to test, is what happens when you bind that string interpolation tag to a function that is self referential... For example:
getServerStatus(){
    this.serverStatus = this.serverStatus + this.serverStatus;
    return this.serverStatus;
}

When I run this code, I notice that the page displays the following:
server with ID 10 is offlineofflineofflineofflineofflineofflineofflineoffline

With exactly 8 repetitions of the serverStatus variable.
What I am wondering is why is this amount exactly 8 repetitions? What logic does angular use to decide that the 'real time' template directive gets cut off from the class property after 8 repetitions.

A: Angular starts two change detecton cycles at the start of application.
In other words, it calls Application.tick() method two times
1) After bootstrapping main component (https://github.com/angular/angular/blob/aaaa34021c2d56f798d20e5a1f31b23972055170/packages/core/src/application_ref.ts#L539-L541)
private _loadComponent(componentRef: ComponentRef<any>): void {
  this.attachView(componentRef.hostView);
  this.tick();

2) And on the first VM turn(when there is no microtask in zonejs) (https://github.com/angular/angular/blob/aaaa34021c2d56f798d20e5a1f31b23972055170/packages/core/src/application_ref.ts#L385-L386)
this._zone.onMicrotaskEmpty.subscribe(
  {next: () => { this._zone.run(() => { this.tick(); }); }});

With this in mind, let's go back to our Application.tick() method. It runs change detection on tree of views(components views or embedded views).
tick(): void {
   ...
    try {
      ...
      this._views.forEach((view) => view.detectChanges());
      if (this._enforceNoNewChanges) {
        this._views.forEach((view) => view.checkNoChanges());
      }
    } catch (e) {
      ...
    } finally {
      ...
    }
}

What can we notice here?
We can notice that in dev mode (because this._enforceNoNewChanges = isDevMode(); https://github.com/angular/angular/blob/aaaa34021c2d56f798d20e5a1f31b23972055170/packages/core/src/application_ref.ts#L383) Angular runs change detection cycle twice. 
Another point here is that the tick method is executed within try catch block.
So, what we have so far?
2 сd cycles * 2 view.detectChanges() on the tree = 4

Also on each view.detectChanges() Angular checks whether template bindings have changed or not. For that Angular executes every expression within template(as a result your getServerStatus() method will be executed on every tree traversal). If during the second cd withih tick method there is some changes in binding then Angular throws the error Expression has changed after it was checked. As you can guess it won't stop subsequent cd cycles thank you try catch block.
For the sake of simplicity let's say you have the following template:
{{ getServerStatus() }}

So what happens here?
Start app                                                              serverStatus 

 loadComponent => tick
                    |
                    |__ view.detectChanges()
                                   ||
                                   \/
                           call getServerStatus()                     'offlineoffline'

                    |__ view.checkNoChanges()
                                  ||
                                  \/
                           call getServerStatus()               'offlineofflineofflineoffline'

               'offlineoffline' !== 'offlineofflineofflineoffline'
                                  ||
                                  \/
    ExpressionChangedAfterItHasBeenCheckedError (template is not updated!!)

 onMicrotaskEmpty => tick
                    |
                    |__ view.detectChanges()
                                   ||
                                   \/
                           call getServerStatus()                     'offline'.repeat(8)

                    |__ view.checkNoChanges()
                                  ||
                                  \/
                           call getServerStatus()                     'offline'.repeat(16)

               'offline'.repeat(8) !== 'offline'.repeat(16)
                                  ||
                                  \/
     ExpressionChangedAfterItHasBeenCheckedError (template is not updated!!)

As a result you get exactly 8 repetitions of serverStatus
