вторая объединенная ветвь игнорируется в XStreams

Я работаю над приложением Cycle JS, используя хранилище и состояние.

Приложение использует xstream как реактивную библиотеку.

Я ограничен в странном поведении.

Мои потоки как на этой диаграмме

введите здесь описание изображения

При первом обновлении сеанса var я получил этот результат отладки:

  • отладка 0
  • отладка 1
  • отладка 3

ПРОБЛЕМА: ветвь "Отладка 2" не выполняется

Если я обновлю элемент сеанса (чтобы создать новое событие хранилища), все две ветки будут выполнены, как и ожидалось.

  • отладка 0
  • отладка 1
  • отладка 2
  • отладка 3

Такое же хорошее поведение произойдет, если добавить .remember() в "debug 0" введите здесь описание изображения

  • отладка 0
  • отладка 1
  • отладка 2
  • отладка 3

Еще более странно, что поток работает должным образом, если я удалю фильтр введите здесь описание изображения

Без фильтра (и без запоминания) поток дает этот результат с момента первого события

  • отладка 0
  • отладка 1
  • отладка 2
  • отладка 3

Я подозреваю, что что-то наблюдается при «отладке 0» до того, как вторая ветвь будет присоединена, и поэтому первое событие уже использовано. Но как это может произойти, если две ветки xs.merged вместе? Как может одна ветка выполняться, а вторая нет? У двух ветвей нет фильтров или другой обработки, они просто сопоставляются с функцией редуктора. Любое предложение о том, как отлаживать и разрешать эти ситуации?


person Fabiano Taioli    schedule 09.06.2019    source источник


Ответы (1)


Проблема возникает из-за того, что storage.session.getItem отправляет как только подписывается, а merge(a$, b$) подписывается на a$ раньше, чем подписывается на b$, поэтому a$ получает событие, но к тому времени, когда b$ подписывается, оно приходит слишком поздно. Эта проблема хорошо известна и называется сбоем (в реактивном программировании) и обычно возникает при наличии потокового графа в форме ромба, как раз в вашем случае.

У меня есть два сообщения в блоге о сбоях, которые могут дать вам больше контекста: Primer on RxJS планировщики и сбои Rx на самом деле не проблема. В нем упоминается RxJS, но xstream довольно близок к RxJS с точки зрения реализации. Разница между xstream и RxJS заключается в том, что потоки xstream всегда многоадресные («общие»), а RxJS имеет много типов планировщика, а xstream — только один. Планировщик по умолчанию в RxJS ведет себя так же, как и в xstream.

Решение состоит в том, чтобы применить .remember() до достижения алмаза. Это связано с тем, что испускаемое значение необходимо кэшировать для других потребителей этого потока. .remember() просто преобразует Stream в MemoryStream. Я думаю, что исходный поток изначально был MemoryStream, и сопоставление MemoryStream создает другие MemoryStream, но filter — это оператор, который нарушает это. filter всегда возвращает поток, и причина этого в том, что MemoryStreams всегда должно иметь текущее значение, но filter может удалять значения, поэтому возможно, что отфильтрованный поток не иметь любую текущую стоимость.

Как автор Cycle.js, я считаю, что способ разработки cyclejs/storage не самый лучший, и я думаю, что мы найдем способы разработки этих API, чтобы свести к минимуму путаницу с MemoryStream и Stream. Но на данный момент важно понимать разницу между ними и планировать свое приложение так, чтобы избежать ромбов (и сбоев) или использовать .remember() в правильных местах.

person André Staltz    schedule 10.06.2019
comment
Спасибо Андре за отличный ответ. Я собираюсь читать сообщения в блоге. Но пытаясь решить проблему, я получил этот странный результат XStream, который я не могу объяснить, даже с вашим текущим разъяснением. Посмотрите на этот код jsfiddle.net/v4dp7rjh. Никаких потоков памяти или предыдущих слушателей. Это бриллиантовый пример, и, как вы предложили, я собираюсь исключить его из приложений, но мне любопытно узнать, почему «фильтр» дает разные результаты в этом случае. - person Fabiano Taioli; 10.06.2019
comment
Моя вина... startWith создает memoryStream :). Теперь я думаю, что понял. Спасибо. - person Fabiano Taioli; 10.06.2019