Горячие и холодные наблюдаемые: есть ли "горячие" и "холодные" операторы?

Я рассмотрел следующий вопрос: " Что такое горячая и холодная наблюдаемые?

Подвести итоги:

  • холодная наблюдаемая испускает свои значения, когда у нее есть наблюдатель, чтобы потреблять их, то есть последовательность значений, полученных наблюдателями, не зависит от времени подписки. Все наблюдатели будут использовать одну и ту же последовательность значений.
  • горячая наблюдаемая выдает значение независимо от своих подписок, то есть значения, полученные наблюдателями, являются функцией времени подписки.

Тем не менее, я чувствую, что жарко против холода все еще является источником путаницы. Итак, вот мои вопросы:

  • Все ли наблюдаемые rx холодны по умолчанию (за исключением субъектов)?

    Я часто читаю, что события являются типичной метафорой для горячих наблюдаемых, но я также читал, что Rx.fromEvent(input, 'click') холодная наблюдаемая (?).

  • Существуют ли / каковы операторы Rx, которые превращают холодные наблюдаемые в горячие наблюдаемые (кроме publish, а также share)?

    Например, как это работает с оператором Rx withLatestFrom? Позволять cold$ быть холодной наблюдаемой, на которую где-то подписаны. Будет sth$.withLatestFrom(cold$,...) быть горячей наблюдаемой?

    Или если я сделаю sth1$.withLatestFrom(cold$,...), sth2$.withLatestFrom(cold$,...) и подписаться на sth1 а также sth2я всегда увижу одно и то же значение для обоих sth?

  • я думал Rx.fromEvent создает холодные наблюдаемые, но это не так, как упоминалось в одном из ответов. Тем не менее, я все еще озадачен этим поведением: http://Codepen%20is%20here%20:%20codepen.io/anon/pen/NqQMJR?editors=101. Разные подписки получают разные значения из одной и той же наблюдаемой. Не был click событие поделился?

4 ответа

Решение

Я возвращаюсь через несколько месяцев к своему первоначальному вопросу и хочу поделиться тем временем полученными знаниями. Я буду использовать следующий код в качестве поддержки объяснения ( jsfiddle):

var ta_count = document.getElementById('ta_count');
var ta_result = document.getElementById('ta_result');
var threshold = 3;

function emits ( who, who_ ) {return function ( x ) {
  who.innerHTML = [who.innerHTML, who_ + " emits " + JSON.stringify(x)].join("\n");
};}

var messages$ = Rx.Observable.create(function (observer){
  var count= 0;
  setInterval(function(){
    observer.onNext(++count);
  }, 1000)
})
.do(emits(ta_count, 'count'))
.map(function(count){return count < threshold})
.do(emits(ta_result, 'result'))

messages$.subscribe(function(){});

Как упоминалось в одном из ответов, определение наблюдаемого приводит к серии обратных вызовов и регистрации параметров. Поток данных должен быть активирован, и это делается через subscribe функция. Подробное описание (упрощенное для иллюстрации) можно найти после этого.

Упрощенная схема

Наблюдаемые значения являются холодными по умолчанию. Подписка на наблюдаемое приведет к созданию восходящей цепочки подписок. Последняя подписка приводит к выполнению функции, которая будет обрабатывать источник и передавать его данные наблюдателю.

Этот наблюдатель, в свою очередь, передает следующему наблюдателю, что приводит к потоку данных вниз по течению вниз к наблюдателю-получателю. Следующая упрощенная иллюстрация показывает подписку и потоки данных, когда два подписчика подписываются на одну и ту же наблюдаемую.

Холодная наблюдаемая упрощенная схема

Горячие наблюдаемые могут быть созданы либо с помощью предмета, либо через multicast оператор (и его производные, см. примечание 3 ниже).

multicast оператор под капюшоном использует предмет и возвращает подключаемое наблюдаемое. Все подписки на оператора будут подписками на внутреннюю тему. когда connect вызывается, внутренний субъект подписывается на наблюдаемую в восходящем направлении, и потоки данных в нисходящем направлении. Субъекты внутренне управляют списком подписанных наблюдателей и многоадресными входящими данными для всех подписанных наблюдателей.

Следующая диаграмма обобщает ситуацию.

Горячая наблюдаемая упрощенная схема

В конце концов, важнее понять поток данных, вызванный шаблоном наблюдателя и реализацией операторов.

Например, если obs жарко, это hotOrCold = obs.op1 холодно или жарко? Каким бы ни был ответ:

  • если нет подписчиков obs.op1никакие данные не будут проходить через op1, Если бы были подписчики на горячие obs, это означает obs.op1 возможно потерял кусочки данных
  • если предположить, что op1 не является групповым оператором, дважды подписывается на hotOrCold подпишусь дважды на op1и каждое значение из obs будет течь дважды op1,

Заметки:

  1. Эта информация должна быть действительной для Rxjs v4. Хотя версия 5 претерпела значительные изменения, большинство из них все еще применяются дословно.
  2. Потоки отмены подписки, ошибок и завершения не представлены, поскольку они не входят в объем вопроса. Планировщики также не учитываются. Помимо всего прочего, они влияют на синхронизацию потока данных, но априори не на его направление и содержание.
  3. В зависимости от типа субъекта, используемого для многоадресной рассылки, существуют различные производные операторы многоадресной рассылки:

Subject type | `Publish` Operator | `Share` operator ------------------ | --------------------------- | ----------------- Rx.Subject | Rx.Observable.publish | share Rx.BehaviorSubject | Rx.Observable.publishValue | shareValue Rx.AsyncSubject | Rx.Observable.publishLast | N/A Rx.ReplaySubject | Rx.Observable.replay | shareReplay

Обновление: см. Также следующие статьи, здесь и там) на эту тему Бен Леш.

Более подробную информацию о предметах можно найти в этом другом вопросе SO: Какова семантика разных предметов RxJS?

Ваше резюме и связанный вопрос верны, я думаю, что терминология может сбить вас с толку. Я предлагаю вам рассматривать горячие и холодные наблюдаемые как активные и пассивные наблюдаемые (соответственно).

То есть активная (горячая) наблюдаемая будет излучать элементы независимо от того, подписан кто-то или нет. Канонический пример, опять же, события нажатия кнопки происходят независимо от того, слушает их кто-то или нет. Это различие важно, потому что, если, например, я нажму кнопку, а затем подпишусь на нажатие кнопки (в таком порядке), я не увижу нажатие кнопки, которое уже произошло.

Пассивная (холодная) наблюдаемая будет ждать, пока не появится подписчик, прежде чем испускать предметы. Представьте себе кнопку, на которой вы не можете нажать на нее, пока кто-то не прослушает события - это гарантирует, что вы всегда будете видеть каждое нажатие.

Являются ли все наблюдаемые Rx "холодными" (или пассивными) по умолчанию? Нет, Rx.fromEvent(input, 'click') например, горячая (или активная) наблюдаемая.

Я также читал, что Rx.fromEvent(input, 'click') холодная наблюдаемая (?)

Это не относится к делу.

Существуют ли Rx-операторы, которые превращают наблюдаемую холодную в наблюдаемую горячую?

Концепция превращения горячей (активной) наблюдаемой в холодную (пассивную) наблюдаемую заключается в следующем: вам нужно записывать события, которые происходят, когда ничего не подписано, и предлагать эти элементы (различными способами) подписчикам, которые появятся в будущем. Один из способов сделать это - использовать тему. Например, вы можете использовать ReplaySubject буферизовать отправленные элементы и воспроизводить их для будущих подписчиков.

Два оператора вы назвали (publish а также share) оба используют предметы внутри, чтобы предложить эту функциональность.

Как это работает с оператором Rx withLatestFrom? Позволять cold$ быть холодной наблюдаемой, на которую был подписан. Будет something$.withLatestFrom(cold$,...) быть горячей наблюдаемой?

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

var clickWith3 = Rx.fromEvent(input, 'click')
    .withLatest(Rx.Observable.from([1, 2, 3]);

Или если я сделаю foo$.withLatestFrom(cold$,...), bar$.withLatestFrom(cold$,...) и подписаться на foo а также barя всегда буду видеть одинаковые значения для обоих?

Не всегда. Опять же, если foo а также bar Например, если нажать на разные кнопки, вы увидите разные значения. Кроме того, даже если они были одной и той же кнопкой, если ваша комбинационная функция (2-й аргумент withLatest) не возвращает один и тот же результат для одних и тех же входных данных, тогда вы не увидите одинаковые значения (потому что он будет вызван дважды, как описано ниже).

я думал Rx.fromEvent создает холодные наблюдаемые, но это не так, как упоминалось в одном из ответов. Тем не менее, я все еще озадачен этим поведением: http://codepen.io/anon/pen/NqQMJR?editors=101. Разные подписки получают разные значения из одной и той же наблюдаемой. Не был click событие поделился?

Я укажу вам этот замечательный ответ от Enigmativity на вопрос, который у меня был о том же поведении. Этот ответ объяснит это намного лучше, чем я, но суть в том, что источник (событие click) является "общим", да, но ваши операции с ним не выполняются. Если вы хотите поделиться не только событием click, но и операцией над ним, вам нужно будет сделать это явно.

values в вашем коде это лениво - ничего не происходит, пока что-то не подпишется, и в этот момент оно проходит и подключается. Итак, в вашем примере, хотя вы подписываетесь на одну и ту же переменную, она создает два разных потока; по одному на каждый звонок подписки.

Вы можете думать о values как генератор потоков для click с этим map прилагается.

.share() в конце этой карты будет создано поведение, которое мы ожидаем, потому что оно неявно подписывается.

Это не ответ на все ваши вопросы (я хотел бы знать их все!), Но наверняка, все fromEvent Наблюдаемые горячие. Кажется, что щелчок происходит не потому, что это не "непрерывное" событие, как mousemove, а в любом случае подписка на источник (addEventListener или же on вызов) выполняется только один раз, когда создается Observable. Так что жарко. Вы можете увидеть это в исходном коде оператора тут и там - созданная наблюдаемая shareне имеет значения, как называется событие или источник.

Другие вопросы по тегам