Оригинальная ссылка:Understanding rxjs BehaviorSubject, ReplaySubject and AsyncSubject
Оригинальный автор:Luuk Gruijs; Опубликовано 4 мая 2018 г.
Переводчик:yk; Если вам нужно перепечатать, пожалуйста, укажитепроисхождение, Спасибо за ваше сотрудничество!
Роль Subject заключается в реализации многоадресной рассылки Observables. Поскольку его выполнение Observable совместно используется несколькими подписчиками, это гарантирует, что каждый подписчик получает абсолютно одинаковые данные. Мало того, что многоадресная рассылка может быть достигнута с помощью Subject, RxJS также предоставляет несколько вариантов Subject для работы с различными сценариями, а именно: BehaviorSubject, ReplaySubject и AsyncSubject.
Если вы не знаете, что такое Subject, я предлагаю вам сначала прочитать мою последнюю статью:Знакомство с темой в rxjs. Если вы считаете, что все в порядке, давайте продолжим!
фотография:Cory Schadt, отUnsplash
BehaviorSubject
BehaviorSubject — это один из вариантов Subject.Свойство BehaviorSubject заключается в том, что он хранит «текущее» значение. Это означает, что вы всегда можете напрямую получить последнее сгенерированное значение BehaviorSubject.
Есть два способа получить «текущее» значение BehaviorSubject: получить доступ к его.valueсвойства или подписаться напрямую. Если вы решите подписаться, то BehaviorSubject отправит текущее сохраненное значение непосредственно подписчику, независимо от того, насколько «старым» является значение. См. пример ниже:
import * as Rx from "rxjs";
const subject = new Rx.BehaviorSubject(Math.random());
// 订阅者 A
subject.subscribe((data) => {
console.log('Subscriber A:', data);
});
subject.next(Math.random());
// 订阅者 B
subject.subscribe((data) => {
console.log('Subscriber B:', data);
});
subject.next(Math.random());
console.log(subject.value)
// 输出
// Subscriber A: 0.24957144215097515
// Subscriber A: 0.8751123892486292
// Subscriber B: 0.8751123892486292
// Subscriber A: 0.1901322109907977
// Subscriber B: 0.1901322109907977
// 0.1901322109907977
Объясните подробно:
- Сначала мы создали тему и зарегистрировали в ней подписчика А. Поскольку subject является BehaviorSubject, абонент A немедленно получает начальное значение subject (случайное число) и одновременно печатает его.
- Затем субъект передает следующее значение. Абонент А снова печатает полученное значение.
- Во-вторых, подпишитесь на тему и назовите ее «Подписчик Б». Аналогично, подписчик B немедленно получит текущее сохраненное значение subject и распечатает его.
- subject снова передает следующее новое значение. В этот момент оба подписчика получат это значение и распечатают его.
- Наконец, мы просто получаем доступ
.valueФорма свойства принимает текущее значение субъекта и печатает его. Это прекрасно работает в синхронных сценариях, потому что вам не нужно подписываться на Subject, чтобы получить его значение.
Кроме того, вы можете обнаружить, что BehaviorSubject необходимо установить с начальным значением при его создании. Этого очень сложно добиться в Observable, но в BehaviorSubject просто передайте значение.
Примечание переводчика: в текущей версии RxJS
BehaviorSubject()Необходимо установить начальное значение, иначе это вызовет ошибку выполнения, а исходный текст этого не отражает. Поэтому я сделал много изменений в этом абзаце, чтобы не вводить читателя в заблуждение. смотрите подробностиBehaviorSubject.
ReplaySubject
В отличие от BehaviorSubject, ReplaySubject может отправлять «старые» данные новым подписчикам. Кроме того, у ReplaySubject есть дополнительная функция, заключающаяся в том, что он может записывать часть наблюдаемого выполнения, таким образом сохраняя некоторые старые данные для «воспроизведения» новым подписчикам.
При создании ReplaySubject вы можете указать объем данных для хранения и срок действия данных. То есть можно реализовать: «переигрывать» новым подписчикам последние пять транслируемых значений в течение секунды перед подпиской. Пример кода выглядит следующим образом:
import * as Rx from "rxjs";
const subject = new Rx.ReplaySubject(2);
// 订阅者 A
subject.subscribe((data) => {
console.log('Subscriber A:', data);
});
subject.next(Math.random())
subject.next(Math.random())
subject.next(Math.random())
// 订阅者 B
subject.subscribe((data) => {
console.log('Subscriber B:', data);
});
subject.next(Math.random());
// Subscriber A: 0.3541746356538569
// Subscriber A: 0.12137498878080955
// Subscriber A: 0.531935186034298
// Subscriber B: 0.12137498878080955
// Subscriber B: 0.531935186034298
// Subscriber A: 0.6664809293975393
// Subscriber B: 0.6664809293975393
Просто прочитайте код:
- Мы создаем ReplaySubject и указываем, что он хранит только значение двух последних трансляций;
- Подпишитесь на тему и назовите ее Подписчик А;
- субъект транслирует три раза подряд, и подписчик А также будет печатать его три раза подряд;
- На этом шаге ReplaySubject делает свое волшебство. Мы снова подписываемся на субъект и называем его Subscriber B, потому что мы указали субъекту для хранения двух последних широковещательных значений, поэтому субъект «повторит» последние два значения для Subscriber B. Мы видим, что подписчик B печатает эти два значения сразу;
- Последняя трансляция темы, оба подписчика получают значение и печатают его.
Ранее вы также можете установить время срока действия данных воспроизведения. Давайте посмотрим на этот пример:
import * as Rx from "rxjs";
const subject = new Rx.ReplaySubject(2, 100);
// 订阅者A
subject.subscribe((data) => {
console.log('Subscriber A:', data);
});
setInterval(() => subject.next(Math.random()), 200);
// 订阅者B
setTimeout(() => {
subject.subscribe((data) => {
console.log('Subscriber B:', data);
});
}, 1000)
// Subscriber A: 0.44524184251927656
// Subscriber A: 0.5802631630066313
// Subscriber A: 0.9792165506699135
// Subscriber A: 0.3239616040117268
// Subscriber A: 0.6845077617520203
// Subscriber B: 0.6845077617520203
// Subscriber A: 0.41269171141525707
// Subscriber B: 0.41269171141525707
// Subscriber A: 0.8211466186035139
// Subscriber B: 0.8211466186035139
Также читайте код:
- Мы создали ReplaysUbject и уточняли его для хранения значения последних двух трансляций, но только для 100 мс;
- Подпишитесь на тему и назовите ее Подписчик А;
- Мы делаем эту тему транслируемой каждые 200 мс. Подписчик A будет получать значение и каждый раз печатать его;
- Мы настраиваем подписку субъекта снова после одной секунды выполнения программы и называем его Subscriber B. Это означает, что субъект провел трансляцию пять раз, прежде чем начал подписываться. Поскольку мы установили время истечения данных на 100 мс и интервал широковещательной рассылки на 200 мс при создании субъекта, подписчик B получит только последнее значение из первых пяти широковещательных сообщений после начала подписки.
AsyncSubject
И BehaviorSubject, и ReplaySubject могут использоваться для хранения некоторых данных, но AsyncSubject отличается. AsyncSubject отправит свое окончательное значение подписчикам только после завершения выполнения Observable. Пожалуйста, смотрите код:
import * as Rx from "rxjs";
const subject = new Rx.AsyncSubject();
// 订阅者A
subject.subscribe((data) => {
console.log('Subscriber A:', data);
});
subject.next(Math.random())
subject.next(Math.random())
subject.next(Math.random())
// 订阅者B
subject.subscribe((data) => {
console.log('Subscriber B:', data);
});
subject.next(Math.random());
subject.complete();
// Subscriber A: 0.4447275989704571
// Subscriber B: 0.4447275989704571
Хотя вывод этого кода невелик, давайте интерпретируем его как обычно:
- Создать асинхронный субъект;
- Подпишитесь на тему и назовите ее Подписчик А;
- тема вещает три раза подряд, но ничего не происходит;
- снова подпишитесь на тему и назовите ее подписчиком Б;
- тема снова вещает, но по-прежнему ничего не происходит;
- тема завершена. Затем оба подписчика получают входящее значение и выводят его на терминал.
В заключение
BehaviorSubject, ReplaySubject и AsyncSubject могут использоваться для многоадресной рассылки точно так же, как и Subject. Каждый из них имеет некоторые дополнительные функции для различных сценариев.
译者注:这个结论好敷衍。 . .