1.rxjs
- Cold Observables 【多次单播】只有被订阅才会产出值,且每次被订阅,都会重新产出值,并只通知本次的订阅者。
- Hot Observables 【单次多播】不管被订阅多少次(包括零),都会进行仅一次的产出值。且一次通知所有订阅者。
第一话
最原始状态
observable,向observer产出值
特点是 【多次单播】,每次被订阅,都重新产出值,每次产出值只能通知一个observer
let Rx = require('rxjs');
let observable = Rx.Observable.create( observer => {
observer.next(Math.random());
observer.next(Math.random());
observer.complete()
});
observable.subscribe(observerA)
observable.subscribe(observerB)
第二话
为了有时候能避免多次单播,设计了只产出一次值的 observable: subject
其特点是 【单次多播】,只产出一次值,且一次能通知所有订阅者
let Rx = require('rxjs');
let subject = new Rx.Subject();
subject.subscribe({
next(value) {
console.log('A:', value)
},
complete() {
console.log('A: complete')
}
});
subject.subscribe({
next(value) {
console.log('B:', value)
},
complete() {
console.log('B: complete')
}
});
subject.next(Math.random());
subject.next(Math.random());
subject.complete();
第三话
subject 除了单独被当做 observable 以外,更重要的用途是帮助传统的observable实现【单次多播】
总结一下两者的特点:
observable 每被订阅一次,就会产出一次值
subject 无论被订阅几次,只会产出一次值
基于此,开发者让 subject 还有 observer 的功能
只要保证observable被一个subject订阅,subject被多个observer订阅,就让observable实现了【单次多播】
subject.subscribe(observerA)
subject.subscribe(observerB)
source$.subscribe(subject)
第四话
observable也能【单次多播】了,
但第三话也还有些瑕疵,
比如不能直观反映出真实的observer和源头observable(记为source$)
改进1
multicast() 结合 connect()
connectable.subscribe(subject)
只是手动调用connect 和 unsubscribe 有些麻烦
let connectable$ = source$.multicast(subject)
connectable$.subscribe(observerA)
connectable$.subscribe(observerB)
connectable$.connect()
connectable$.unsubscribe()
第五话
改进2
multicast() 结合 refCount(),改进第四话需手动调用connect 和 unsubscribe的缺点
multicast(subject) 需要手动传入一个Subject的实例,还可简化
let connectable$ = source$
.multicast(subject)
.refCount()
connectable$.subscribe(observerA)
connectable$.subscribe(observerB)
第六话
改进3
publish() 代替 multicast(subject)
publish() === multicast(subject)
与上面的改进2 都存在同一个特征:
For all new subscribers if Source has completed they will receive “completed” emits,
but if Source has not completed Subject will re-subscribe to Source
let source$ = Rx.Observable.create(observer => {
observer.next(1);
observer.next(2);
observer.complete()
})
let connectable$ = source$
.publish()
.refCount()
let observerA = {
next(val) {console.log('A:',val)},
complete() {console.log('A:finished')}
}
let observerB = {
next(val) {console.log('B:', val)},
complete() {console.log('B:finished')}
}
connectable$.subscribe(observerA)
connectable$.subscribe(observerB)
代码中的 observerB 实际上拿不到值
因为:
source$ 被一个 Subject 实例 subject 订阅,subject 被多个 observer 订阅,subject 是中间人
source$(冷) 的特征是每被订阅一次,就产出值一次
subject 的特征是被订阅多次,只产出值一次
因为中间人 subject 只产出一次值,而到observerB时已经结束
所以结果是
A:value1
A:value2
...
A:finished
B:finished
第七话
改进4
改进3中说过,中间人 subject 只产出一次值,所以 observerB 也就拿不到值了
那么如果再生成一个中间人 subject2 ,再去订阅source$ 一次,问题就可解决
所以调用 multicast 的时候,就不要传 Subject 的实例了,改为传一个工厂函数
share() 代替 publish().refCount()
publish().refCount() === multicast(subject).refCount()
share() === multicast(SubjectFactory).refCount()
share():For any new subscriber no matter if Source has been completed or not,
it will subscribe to Source again using new Subject
let connectable$ = source$
.share()
let observerA = {
next(val) {console.log('A:',val)},
complete() {console.log('A:finished')}
}
let observerB = {
next(val) {console.log('B:', val)},
complete() {console.log('B:finished')}
}
connectable$.subscribe(observerA)
connectable$.subscribe(observerB)
总结上面的部分过程,单播变多播的几种方式:
multicast(new Subject()).refCount()
publish().refCount()
share()
Subject 还有其他“变种”,根据变种的不同还有如下方法
变种1 ReplaySubject // 被新订阅时,重新产出最后 n 个值
multicast(new ReplaySubject()).refCount()
publishReplay().refCount()
shareReplay()
变种2 BehaviorSubject // 产出当前最新值
multicast(new BehaviorSubject())
publishBehavior().refCount()
变种3 AsyncSubject // 产出最后一个值
multicast(new AsyncSubject())
publishLast().refCount()