概述
Observable本身并没有冷或者热的属性,而基于生产数据的方式可以将其分为冷或者热两类,下面是两者之间的一些异同点。
- cold observable是指每个订阅者都有自己的数据生产者,而hot observable是指所有订阅者共享一个数据生产者。
- cold observable的数据生产者是在订阅时创建和激活的,而hot observable的数据生产者是在声明时创建和激活的。
- cold observable通常用于一次性或有限次数的数据流,例如http请求或文件读取,而hot observable通常用于无限或持续性的数据流,例如时间间隔函数(interval)或鼠标移动(mouse move event)。
- cold observable可以通过一些操作符(如share、publish、multicast等)转换为hot observable,反之亦然。
此外,用一个经典的看电影的例子可以更形象地描述出二者的差异。
对于cold observable,可以认为是通过视频网站看电影,每个人的观看进度都是独立的(独立),彼此之间互不影响。
对于hot observable,可以认为是去电影院看电影,一个放映室一个时间段的观众看的都是一个电影(共享)。当观众迟到时,只能从当前电影已经播放到的进度开始看起。
代码实例
Cold observable 实例
let obs = interval(1000);
obs.subscribe(v => console.log("1st subscriber:" + v));
// 错开时间,否则无法判断是hot还是cold observable
setTimeout(() => obs.subscribe(v => console.log("2nd subscriber:" + v)), 1000);
输出:
1st subscriber:0
1st subscriber:1
2nd subscriber:0
1st subscriber:2
2nd subscriber:1
1st subscriber:3
...
可以看出1st subscriber和2nd subscriber 获取到的数字序列是独立的,每个subscriber都是获取到的序列都是从0开始。
Cold observable => hot? observable
方式一(使用publish函数)
let obs = interval(1000).pipe(publish(), refCount());
obs.subscribe(v => console.log("1st subscriber:" + v));
setTimeout(() => obs.subscribe(v => console.log("2nd subscriber:" + v)), 1000);
输出:
1st subscriber:0
1st subscriber:1
2nd subscriber:1
1st subscriber:2
2nd subscriber:2
...
这里可以看出,1秒后,1st subscriber和2nd subscriber获取到的序列开始一致,它们共享了数据源。
我们通过publish函数创建了一个ConnectableObservable对象(ConnectableObservable需要使用 connect方法激活,否则将不会发送数据),意味着所有的订阅者将共享一个数据源,随后的refCount函数表示当有第一个订阅者以后开始发射数据。因此1st subscriber将首先获取到0,一秒后2nd subscriber出现,两个订阅者开始共享了数据源。
方式二(使用Subject)
let obs = interval(1000).pipe(multicast(new Subject()), refCount());
obs.subscribe(v => console.log("1st subscriber:" + v));
setTimeout(() => obs.subscribe(v => console.log("2nd subscriber:" + v)), 1000);
输出:
1st subscriber:0
1st subscriber:1
2nd subscriber:1
1st subscriber:2
2nd subscriber:2
...
Subject是一种特殊的observable,它可以实现multicast。可以使用Subject作为一个连接器,将一个普通的observable转换成一个支持multicast的hot observable。
最后,观察两种方式的输出其实可以发现,这个 'hot' observable 并不真的hot,这点从refCount函数的功能也可以看出来,当出现了第一个订阅者之后,observable才开始发送数据,并不符合所谓 hot observable的定义(hot observable的数据生产者是在声明时创建和激活的),因此还可以通过提前对ConnectableObservable对象调用connect方法使得observable真正的hot起来。
let obs = interval(1000).pipe(publish()) as ConnectableObservable<number>;
obs.connect();
setTimeout(() => obs.subscribe((v: number) => console.log("1st subscriber:" + v)), 1000);
setTimeout(() => obs.subscribe((v: number) => console.log("2nd subscriber:" + v)), 2000);
1st subscriber:1
1st subscriber:2
2nd subscriber:2
1st subscriber:3
2nd subscriber:3
...
显然,第一个订阅者订阅之前,observable已经开始发射数据。
参考
What are the Hot and Cold observables?