Фильтрация объекта BehaviorSubject

#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 так, чтобы он печатал данные в указанное мной время. Я вернусь, чтобы попытаться перефразировать вопрос.