class Subject {
private fns: Array<(value: T) => void> = []
public next(value: T) {
this.fns.forEach(fn => fn(value))
}
public subscribe(fn: (value: T) => void) {
this.fns.push(fn)
return () => {
this.fns = this.fns.filter(x => x !== fn)
}
}
}
副作用管理也没有什么 magic,它依赖于第4行,当没有任何 subscription
时,便不会调用任何函数,即逻辑不会继续往下执行。
Observable
就是没有 next
的 Subject
。通常是由单一的数据源进行控制,一般来说,不需要开发者自己去调用构造函数,最常见的是来自于 pipe
的返回值。
ReplaySubject
内部有一个保存 value
的数组,在第4行前会记录一下当前的 value
,每当有一个新的 Subscription
,会把最近 n 项的 value
重播给订阅方。
BehaviorSubject
相当于 n 为 1 的 ReplaySubject
。因为比 ReplaySubject
常用,所以单独成为了一个类。我还真没怎么用过 ReplaySubject
。
pipe
用于连接 Observable
,一般主要逻辑都会放在其中执行。一般来说,其中逻辑是否执行有两个必要条件:
•输出流在 pipe
之后产生值•BehaviorSubject
和 ReplaySubject
在有新的 subscription
的时候会发出当前值,所以作为输入时必产生值•有订阅(subscribe
)方•例外:shareReplay
pipe
的原理是链式(reduce
)调用 innerSubscribe
函数,和 subscribe
的区别在于,不会触发副作用的执行。
对于输入流的每次 next
调用,pipe
中逻辑的默认执行次数为订阅方的数量。在绝大多数情况下,不希望逻辑执行多遍,于是需要使用多播。很多文档把多播说的非常复杂,个人觉得没有必要,懂这两个 operator
就行:share
、shareReplay
。把这两个 operator
放在 pipe
的最后一个位置,即可保证前面的逻辑执行次数与订阅方数量无关。不同的是,shareReplay
不管有没有订阅方,都会执行逻辑,而 share
必须存在第一个订阅方之后才开始执行逻辑。
使用 shareReplay
的又叫做热流,其他叫做冷流。在有订阅时,冷流开始执行逻辑,在无订阅时,冷流终止逻辑,冷流具有 rxjs 的核心优势:副作用管理。热流与是否订阅无关,在没有订阅时,也不会终止逻辑。因此,个人很少把 shareReplay
与异步结合使用。
参考资料:可以深入了解[1]
引用链接
[1]
可以深入了解: https://blog.thoughtram.io/angular/2016/06/16/cold-vs-hot-observables.html#hot-vs-cold-observables
综上,使用 rxjs 包装逻辑的基本结构如下:
const input$ = new Subject();
const output$ = new BehaviorSubject(initValue);
const subscription = input$.pipe(
operator1(),
operator2(),
).subscribe(output => output$.next(output));
•约定:在 UI 层消费数据时,input$ 结尾的流仅可使用 next
;output$ 结尾的流仅可使用 su