介绍
在 RxJS 中,一个 _subject 是一个特殊的混合物,可以同时作为可观察者和观察者,从而将数据推到对象中,而对象的订阅者则会接收这些推出的数据。
对象有用用于多元化或当数据源不易转化为可观察的时。 易于过度使用对象,并且通常,如在 这篇优秀文章中所示,当可以创建可观察的源时,可以避免对象。
在本文中,您将了解主题,行为主题和重播主题。
前提条件
如果您想跟随这篇文章,您将需要:
- Some familiarity with RxJS observables and observers.
本教程是用「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 subjects 或 replay 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
,Error
或Complete
。
行为错误
当一个主题完成或错误,所有内部订阅也完成或错误:
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操作员来宣告性地管理订阅。