如何使用 RxJS 主题、行为主题和重放主题

介绍

在 RxJS 中,一个 _subject 是一个特殊的混合物,可以同时作为可观察者和观察者,从而将数据推到对象中,而对象的订阅者则会接收这些推出的数据。

对象有用用于多元化或当数据源不易转化为可观察的时。 易于过度使用对象,并且通常,如在 这篇优秀文章中所示,当可以创建可观察的源时,可以避免对象。

在本文中,您将了解主题,行为主题和重播主题。

前提条件

如果您想跟随这篇文章,您将需要:

本教程是用「rxjs」 v7.3.0 验证的。

使用主题

创建主题从 RxJS 的主题的新实例开始:

1const mySubject = new Rx.Subject();

可以创建多个订阅,并且内部的主题将保持订阅列表:

1const subscription1 = mySubject.subscribe(x => console.log(`${x} ${x}`));
2
3const subscription2 = mySubject.subscribe(x => console.log(x.toUpperCase()));

数据可以通过其下一步方法推入主体:

1mySubject.next('Hello!');

运行此脚本将产生以下输出:

1[secondary_label Output]
2Hello! Hello!
3HELLO!

对于subscription1,此代码将输入并显示两次,对于subscription2,此代码将输入并应用toUpperCase()

当数据被推到一个主题时,它将通过其内部订阅列表,并接下来将数据输入到每一个。

将数据推向订阅

以下是一个示例,展示了如何将数据推向订阅:

 1const mySubject = new Rx.Subject();
 2
 3mySubject.next(1);
 4
 5const subscription1 = mySubject.subscribe(x => {
 6  console.log('From subscription 1:', x);
 7});
 8
 9mySubject.next(2);
10
11const subscription2 = mySubject.subscribe(x => {
12  console.log('From subscription 2:', x);
13});
14
15mySubject.next(3);
16
17subscription1.unsubscribe();
18
19mySubject.next(4);

使用此示例,以下是将打印在控制台上的结果:

1[secondary_label Output]
2From subscription 1: 2
3From subscription 1: 3
4From subscription 2: 3
5From subscription 2: 4

注意到迟到的订阅如何在被推入主题的数据中丢失,我们将看到如何用 behavior subjectsreplay subjects 解决此问题。

多元化数据到所有订阅

对象的真正力量在 multicasting 中发挥作用,其中一个对象作为观察者传递给一个可观察的,这意味着,当可观察的发射时,数据将被多发送到对象的所有订阅:

这里有一个例子,一个trickleWords可观察的每750秒发出一个单词。

 1const mySubject = new Rx.Subject();
 2
 3const words = ['Hot Dog', 'Pizza', 'Hamburger'];
 4
 5const trickleWords = Rx.Observable.zip(
 6  Rx.Observable.from(words),
 7  Rx.Observable.interval(750),
 8  word => word
 9);
10
11const subscription1 = mySubject.subscribe(x => {
12  console.log(x.toUpperCase());
13});
14
15const subscription2 = mySubject.subscribe(x => {
16  console.log(
17    x
18      .toLowerCase()
19      .split('')
20      .reverse()
21      .join('')
22  );
23});
24
25trickleWords.subscribe(mySubject);

在所有值被发出后,将产生以下输出:

1[secondary_label Output]
2HOT DOG
3god toh
4PIZZA
5azzip
6HAMBURGER
7regrubmah

对于订阅1,words的数组已被修改为toUpperCase();对于subscription2,words的数组已被修改为toLowerCase()reverse()

使用可观察

asObservable 运算符可以用来将一个对象转化为可观察的对象,当你想暴露对象的数据时,这可能是有用的,但同时可以防止数据被意外推入对象:

1const mySubject = new Rx.Subject();
2const myObservable = mySubject.asObservable();
3
4mySubject.next('Hello');
5myObservable.next('World!');

这将产生以下产出:

1[secondary_label Output]
2TypeError: myObservable.next is not a function

myObservable没有Next,ErrorComplete

行为错误

当一个主题完成或错误,所有内部订阅也完成或错误:

 1const mySubject = new Rx.Subject();
 2
 3const subscription1 = mySubject.subscribe(null, error =>
 4  console.log('From subscription 1:', error.message)
 5);
 6
 7const subscription2 = mySubject.subscribe(null, error =>
 8  console.log('From subscription 2:', error.message)
 9);
10
11mySubject.error(new Error('Error!'));

这将产生以下产出:

1[secondary_label Output]
2From subscription 1: Error!
3From subscription 2: Error!

已生成错误消息。

使用 Replay 主题

如前所述,晚期主題訂閱會錯過之前發佈的數據。 Replay subjects 可以通過保留以往值的缓存來幫助新訂閱。

以下是对重播主题的使用示例,在新订阅中保留和发行2个以前值的缓冲:

 1const mySubject = new Rx.ReplaySubject(2);
 2
 3mySubject.next(1);
 4mySubject.next(2);
 5mySubject.next(3);
 6mySubject.next(4);
 7
 8mySubject.subscribe(x => {
 9  console.log('From subscription 1:', x);
10});
11
12mySubject.next(5);
13
14mySubject.subscribe(x => {
15  console.log('From subscription 2:', x);
16});

这将产生以下产出:

1[secondary_label Output]
2From subscription 1: 3
3From subscription 1: 4
4From subscription 1: 5
5From subscription 2: 4
6From subscription 2: 5

存储了 2 个值的缓冲器。

使用行为对象

行为对象类似于重播对象,但如果以前没有发行任何值,只会重新发出最后发行值或默认值:

 1const mySubject = new Rx.BehaviorSubject('Hello!');
 2
 3mySubject.subscribe(x => {
 4  console.log('From subscription 1:', x);
 5});
 6
 7mySubject.next(5);
 8
 9mySubject.subscribe(x => {
10  console.log('From subscription 2:', x);
11});

这将产生以下产出:

1[secondary_label Output]
2From subscription 1: Hello!
3From subscription 1: 5
4From subscription 2: 5

默认值Hello!被发行。

结论

在本文中,您了解了主题,行为主题和重播主题。

继续你的学习与 介绍RxJS缓冲操作员, RxJS:从操作员,以及 如何使用 takeUntil RxJS操作员来宣告性地管理订阅

Published At
Categories with 技术
Tagged with
comments powered by Disqus