La tua ultima soluzione è l'unica corretta.
Le altre due soluzioni non dovrebbero funzionare come previsto. In realtà, ciò dovrebbe comportare un ciclo infinito.
Ciò è dovuto al funzionamento di eventloop di JavaScript . L'immagine seguente mostra un modello del runtime JavaScript (L'immagine è stata presa da qui ):

Le parti rilevanti per noi sono il stacke il queue. Un runtime JavaScript elabora i messaggi suqueue . Ogni messaggio è associato a una funzione che viene chiamata durante l'elaborazione del messaggio.
Per lo stack, ogni chiamata di funzione crea un frame nello stack che contiene gli argomenti delle funzioni e le variabili locali. Se una funzione chiama un'altra funzione, viene inserito un nuovo frame in cima allo stack. Quando una funzione ritorna, il frame superiore viene estratto dallo stack.
Ora se lo stack è vuoto il runtime JavaScript elaborerà il messaggio successivo sul queue(il più vecchio).
Se si utilizza setTimeout(() => doSomething(),100), la doSomething()funzione viene aggiunta alla coda dopo 100 millisecondi. Questo è il motivo per cui i 100 millisecondi non sono un tempo garantito ma un tempo minimo. Quindi doSomething methodviene chiamato solo se lo stack è vuoto e nient'altro è in coda.
Ma mentre stai iterando in un ciclo while e la tua condizione dipende dal codice all'interno del tuo setTimeout, hai creato un ciclo infinito perché lo stack non si svuoterà e quindi il tuo this.posts.push(this.postService.next(10));codice non verrà mai chiamato.
Per le implementazioni RxJS lo stesso vale. Usano gli scheduler per gestire i tempi. Esistono diverse implementazioni dello scheduler interno in RxJS, ma come possiamo vedere nelle implementazioni per intervale timer, se non specifichiamo uno scheduler, quello predefinito è asyncScheduler. Le pianificazioni asyncScheduler funzionano con le setIntervalquali funzionano come setTimeoutmenzionato sopra e inseriscono un altro messaggio in coda.
Ho provato le tue due soluzioni con il ciclo while e in realtà il primo ha bloccato completamente il mio browser, mentre il secondo era molto lento ma poteva inviare qualcosa alla console all'interno del ciclo while. In realtà non so perché il secondo sia un po 'più performante, ma entrambi non sono quello che vuoi davvero. Hai già trovato una buona soluzione e spero che questa risposta possa aiutarti a capire perché le prime soluzioni funzionano così male.