24.angular的一些零散知识(三)

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()
6.JIT\AOT区别
7.entryComponent

你可能感兴趣的