Ваше последнее решение - единственно правильное.
Два других решения не должны работать так, как вы ожидали. На самом деле, это должно привести к бесконечному циклу.
Это из-за того, как работает Eventloop JavaScript . На следующем рисунке показана модель среды выполнения JavaScript (изображение было взято отсюда ):

Для нас важными частями являются stackи queue. Среда выполнения JavaScript обрабатывает сообщения в queue. Каждое сообщение связано с функцией, которая вызывается при обработке сообщения.
Для стека каждый вызов функции создает в стеке фрейм, содержащий аргументы функций и локальные переменные. Если функция вызывает другую функцию, новый кадр помещается поверх стека. Когда функция возвращает верхний кадр, он выталкивается из стека.
Теперь, если стек пуст, среда выполнения JavaScript будет обрабатывать следующее сообщение queue(самое старое).
Если вы используете setTimeout(() => doSomething(),100), doSomething()функция добавляется в очередь через 100 миллисекунд. По этой причине 100 миллисекунд - это не гарантированное время, а минимальное время. Следовательно, ваш doSomething methodвызов вызывается только в том случае, если стек пуст и в очереди больше ничего нет.
Но поскольку вы выполняете итерацию в цикле while, и ваше состояние зависит от кода внутри вашего setTimeout, вы создали бесконечный цикл, потому что стек не опустеет и, следовательно, ваш this.posts.push(this.postService.next(10));код никогда не будет вызываться.
Для реализаций RxJS то же самое верно. Они используют планировщики для обработки времени. Существуют разные реализации внутреннего планировщика в RxJS, но, как мы видим из реализаций для intervalи timer, если мы не указываем планировщик, по умолчанию используется asyncScheduler. AsyncScheduler планирует работу, setIntervalкоторая работает как setTimeoutуказано выше, и помещает другое сообщение в очередь.
Я попробовал два ваших решения с циклом while, и фактически первое полностью заморозило мой браузер, в то время как второе было очень медленным, но могло выводить что-то на консоль внутри цикла while. Я на самом деле не знаю, почему второй немного более производительный, но, тем не менее, оба не то, что вы на самом деле хотите. Вы уже нашли хорошее решение, и я надеюсь, что этот ответ поможет вам понять, почему первые решения работают так плохо.