Ваше последнее решение - единственно правильное.
Два других решения не должны работать так, как вы ожидали. На самом деле, это должно привести к бесконечному циклу.
Это из-за того, как работает 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. Я на самом деле не знаю, почему второй немного более производительный, но, тем не менее, оба не то, что вы на самом деле хотите. Вы уже нашли хорошее решение, и я надеюсь, что этот ответ поможет вам понять, почему первые решения работают так плохо.