Angular 4 setTimeout does not wait

Yes, you're doing it wrong: you have a loop telling 4 times in a row to execute timer() 3 seconds later, from now.

To do what you want, you would have to reschedule the next timer each time timer() is called, or, more simply, to use setInterval():

let count = 0;
const interval = window.setInterval(() => {
    this.timer();
    count++;
    if (count >= 4) {
        window.clearInterval(interval);
    }
}, 3000); 

Note that, since you're using angular, using observables would be muuuch easier:

Observable.interval(3000).take(4).subscribe(() => this.timer());

I did it with Angular 6. This code requests every 5 seconds to get the progress of rendering. It will stops sending request when the progress reaches %100.

import {interval} from "rxjs";

getProgress(searchId): void{
const subscription = interval(5000)
  .subscribe(()=>{
    //Get progress status from the service every 5 seconds
    this.appService.getProgressStatus(searchId)
      .subscribe((jsonResult:any)=>{
          //update the progress on UI 

          //cancel subscribe until it reaches %100
          if(progressPercentage === 100)
            subscription.unsubscribe();
        },
        error => {
          //show errors
        }
      );
  });
}

Since you are using Angular you can probably do this in a much simpler way using takeWhile:

Observable.interval(10000)
    .takeWhile(() => !stopCondition)
    .subscribe(i => { 
        // This will be called every 10 seconds until `stopCondition` flag is set to true
    })

This is indeed not the way to use an async method. The while loop just goes 4 times through it in one go, and initiate the 4 timers. Which will output simultaneously as well in 3 seconds. You can however leverage the await and async functionality from TypeScript:

public stopCondition: boolean = false;

public async run(): Promise<void> {
    while (!this.stopCondition) {
       await new Promise<void>(resolve => {
           setTimeout(resolve, 10000);
       });
       this.execute();
    }
    console.log('done');
}

public execute(): void {
    if ('whatever should trigger your stop condition') {
       this.stopCondition = true;
    }
}

This will run the execute method after every 10 seconds, for as long as the stopCondition === false. When the stopCondition === true it will output done.