Twoje ostatnie rozwiązanie jest jedyne prawidłowe.
Pozostałe dwa rozwiązania nie powinny działać tak, jak się spodziewałeś. W rzeczywistości powinno to doprowadzić do nieskończonej pętli.
Wynika to z tego, jak działa Eventloop JavaScript . Poniższe zdjęcie pokazuje model środowiska wykonawczego JavaScript (Zdjęcie zostało zrobione stąd ):
Odpowiednie dla nas części to stack
i queue
. Środowisko wykonawcze JavaScript przetwarza wiadomości w queue
. Każda wiadomość jest powiązana z funkcją, która jest wywoływana podczas przetwarzania wiadomości.
Dla stosu każde wywołanie funkcji tworzy ramkę na stosie, która zawiera argumenty funkcji i zmienne lokalne. Jeśli funkcja wywołuje inną funkcję, nowa ramka jest umieszczana na stosie. Kiedy funkcja zwraca, górna ramka jest wyskakiwana ze stosu.
Teraz, jeśli stos jest pusty, środowisko wykonawcze JavaScript przetworzy następną wiadomość na queue
(najstarszym).
Jeśli użyjesz setTimeout(() => doSomething(),100)
, doSomething()
funkcja zostanie dodana do kolejki po 100 milisekundach. To jest powód, dla którego 100 milisekund nie jest gwarantowanym czasem, ale czasem minimalnym. Dlatego twoja doSomething method
jest wywoływana tylko wtedy, gdy stos jest pusty i nic więcej nie znajduje się w kolejce.
Ale gdy iterujesz w pętli while, a twój stan zależy od kodu wewnątrz setTimeout
, stworzyłeś nieskończoną pętlę, ponieważ stos nie będzie pusty i dlatego twój this.posts.push(this.postService.next(10));
kod nigdy nie zostanie wywołany.
To samo dotyczy implementacji RxJS. Używają harmonogramów do obsługi czasu. Istnieją różne implementacje wewnętrznego harmonogramu w RxJS, ale jak widzimy w implementacjach dla interval
i timer
, jeśli nie określimy harmonogramu, domyślnym jest asyncScheduler. Harmonogramy asyncScheduler działają z tymi, setInterval
które działają jak setTimeout
wspomniano powyżej, i wypychają kolejny komunikat do kolejki.
Wypróbowałem twoje dwa rozwiązania z pętlą while i tak naprawdę pierwsze całkowicie zamroziło moją przeglądarkę, podczas gdy drugie było bardzo opóźnione, ale mogło wysyłać coś do konsoli wewnątrz pętli while. Właściwie nie wiem, dlaczego ten drugi jest nieco bardziej wydajny, ale mimo to oba nie są tym, czego naprawdę chcesz. Znalazłeś już dobre rozwiązanie i mam nadzieję, że ta odpowiedź pomoże ci zrozumieć, dlaczego pierwsze rozwiązania działają tak źle.