#rxjs
#rxjs
Вопрос:
У меня есть, BehaviorSubject
что я хотел бы иметь возможность filter
, но поддерживать качество, подобное поведению субъекта, чтобы новые подписчики всегда получали значение при подписке, даже если последнее переданное значение было отфильтровано. Есть ли краткий способ сделать это, используя встроенные функции из rxjs? Например:
const isEven = (n) => n % 2 === 0;
const source = new BehaviorSubject(1);
const stream = source.pipe(filter(isEven));
stream.subscribe((n) => console.log(n)); // <- I want this to print `1`
source.next(2); // prints `2`; that's good
source.next(3); // does not print anything; that's good
Я написал свою собственную реализацию, но предпочел бы более простое решение с использованием существующих операторов вместо этого, если это просто.
Ответ №1:
Просто используйте второй объект BehaviorSubject
const { BehaviorSubject } = rxjs;
const { filter} = rxjs.operators;
const isEven = (n) => n % 2 === 0;
const source = new BehaviorSubject(1);
const stream = new BehaviorSubject(source.getValue());
source.pipe(filter(isEven)).subscribe(stream);
stream.subscribe(val => { console.log(val); });
source.next(2);
source.next(3);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.4.0/rxjs.umd.min.js"></script>
Комментарии:
1. Хорошо, это довольно просто. Прохладный. Я думаю, что средняя часть также может быть упрощена до
source.pipe(filter(isEven)).subscribe(stream)
.2. Я понял, что после того, как я ушел с работы, было поздно в пятницу днем, и звонил beer o’clock.
3. Как бы вы сделали это таким образом, чтобы, если фильтр равен false,
stream
присваивалось значение по умолчанию вместо того, чтобы просто вообще не получать новое значение?4. Похоже, что я должен использовать
map
вместоfilter
(простите за мою новизну в RxJS)
Ответ №2:
Ответ Адриана заслуживает похвалы, похоже, что он отвечает наилучшим образом, учитывая встроенные операторы, доступные с rxjs
самим собой. Это не совсем соответствовало моим потребностям, поэтому я опубликовал свой пользовательский оператор в своей маленькой библиотеке s-rxjs-utils
. Это он вызвал filterBehavior()
. Из документов:
Работает аналогично
filter()
, но всегда пропускает первую эмиссию для каждого нового подписчика. Это делает его подходящим для подписчиков, которые ожидают, что observable будет вести себя какBehaviorSubject
, где первое излучение обрабатывается синхронно во время вызоваsubscribe()
(например,async
канал в шаблоне Angular).
Ответ №3:
Ваш stream
уже передан для использования isEven
фильтра, поэтому ваше начальное значение 1 не отображается в вашей консоли, ведет себя так, как ожидалось.
Если вы хотите увидеть свое начальное значение, равное 1, подпишитесь непосредственно на BehaviourSubject
:
const isEven = (n) => n % 2 === 0;
const source = new BehaviorSubject(1);
const stream = source.pipe(filter(isEven));
// should print 1, and should print 2 and 3 when your source is nexted.
source.subscribe((n) => console.log(n));
stream.subscribe((n) => console.log(n)); // <- should NOT Print 1, because it has been filtered
source.next(2); // prints `2`; that's good
source.next(3); // does not print anything; that's good
Комментарии:
1. Извините — я, должно быть, неправильно сформулировал свой вопрос. Я знаю, что поэтому он ведет себя по-другому, я хочу знать, как заставить его вести себя таким образом. Я хочу знать, как сконструировать
stream
так, чтобы он печатал данные в указанное мной время. Я вернусь, чтобы попытаться перефразировать вопрос.