Поведение здесь неинтуитивно, потому что Subject
имеют семантику, отличную от обычных Observables.
В документации , Subject
s имеют семантику, аналогичную EventEmitter
s: они отслеживают своих подписчиков внутри и синхронно вызывают всех слушателей , когда новое событие отправлено.
В вашем примере оператор tap
синхронно передает новые события в data$
Observable. Поэтому каждый раз, когда он вызывает next()
, он немедленно запускает цепочку pipe
для нового значения , прежде чем возвращается обработчик tap()
.
Чтобы лучше наблюдать это поведение, в этом примере регистрирует, когда оператор tap
входит и выходит, а также печатает стек.
Когда вы запустите пример, вы увидите, что цепочка pipe
работает для 1111
и 2333
до того, как вернется окончательный обработчик tap
для 2
. Вы также увидите, что стек вызовов событий 1111
и 2333
по-прежнему содержит вызовы pipe
/ tap
для события 2
.
Почему наблюдаемая emit$
имеет события в другом порядке? emit$
подписан непосредственно на Subject
, поэтому его слушатель синхронно запускается, как только вызывается next
. С точки зрения emit$
, порядок вызовов next
составляет [1, 2, 2333, 1111]
.
datas$
, с другой стороны, должен ждать, пока окончательный оператор tap()
не вернется, прежде чем вызывать абонента. Поэтому, когда событие 2
проходит через финальный tap
, datas$
не видит его, пока не завершится обработка 1111
и 2333
.
Должны ли вы выдавать новые значения в операторах?
Обычно нет. Зачем? Потому что очень трудно понять, что происходит, даже в относительно простом примере, подобном этому (где все называется синхронно).
Представьте себе, если в этот пример каким-то образом была включена обычная не-предметная наблюдаемая. Порядок операций будет чрезвычайно трудно отследить, и стек вызовов становится менее полезным для отладки, поскольку он очищается для каждого тика цикла обработки событий.
В общем случае генерировать новые значения в операторах, только если вы уверены, что вам нужна точная семантика . Если есть способ представить свою логику без этого (например, с помощью обычных не-предметных наблюдаемых) или, что еще лучше, вообще без использования Subject
s, тогда будет гораздо проще рассуждать о коде.