RxJs:Observable 是有状态的吗?
RxJs: Is Observable stateful?
我问这个是因为我尝试了以下代码:
//RxJs v5.5.2; NodeJs v7.10.1
var Rx = require('rxjs/Rx');
var observable = Rx.Observable.of(1,2,3);
var sub = observable.subscribe(console.log);
var sub1 = observable.subscribe(console.log);
它输出 1 2 3 1 2 3(省略新行)。
但是,正如RxJs的文档所说,Observable是一个stream,为什么第二个订阅就拿到了所有的值呢?我的理解是,在第一次订阅之后,observable 已经完成并且作为一个流,它不应该产生它已经发出的值。
我是不是误会了什么?
根据上面引用的文章,Hot vs Cold Observables
Observables are just functions!
Observables are functions that tie an observer to a producer. That’s it. They don’t necessarily set up the producer, they just set up an observer to listen to the producer, and generally return a teardown mechanism to remove that listener. The act of subscription is the act of “calling” the observable like a function, and passing it an observer.
因此,observable 只是生产者和观察者之间的管道,生产者可以(通常)拥有状态 'baked in'。
试图证明在你的例子中某处有一个生产者 Rx.Observable.of(1,2,3)
有点困难。
Observable.of 的来源是
export const of = ArrayObservable.of;
和数组Observable.of
static of<T>(...array: Array<T | IScheduler>): Observable<T> {
所以在这种情况下传播运算符是 生产者,array
是传递给 Observable 的状态。
我找不到扩展运算符的源代码,但是这个参考 es6-equivalents-in-es5#spread-operator 给出了以下 es5 等价物
var _toArray = function (arr) {
return Array.isArray(arr) ? arr : [].slice.call(arr);
};
function add(a, b) {
return a + b;
}
var nums = [5, 4];
console.log(add.apply(null, _toArray(nums)));
假设上面的 _toArray()
是价差的合理近似值,我们可以说价差本质上是生产者函数。
那么,Rx.Observable.of(1,2,3)
有状态吗?我们可以说是的,因为该语句包含状态,但等效于
const nums = [1,2,3]
const src = Rx.Observable.of(...nums)
我们可以看到状态实际上是可观察对象的外部。
热的呢?
一个热的可观察对象有一个生产者,它没有按需复制它的值,例如事件。
因此,当生产者很热时,可观察对象不会 'remember' 在管道设置之前状态(即发生订阅时),因此 生产者 的状态不是可观察的。
console.clear()
const eventEmitter = new EventEmitter();
var source = Rx.Observable.fromEvent(eventEmitter, 'data')
eventEmitter.emit('data', 1);
eventEmitter.emit('data', 2);
source.subscribe(x => console.log('subscription', x))
eventEmitter.emit('data', 3);
eventEmitter.emit('data', 4);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.2/Rx.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/EventEmitter/5.2.4/EventEmitter.js"></script>
我问这个是因为我尝试了以下代码:
//RxJs v5.5.2; NodeJs v7.10.1
var Rx = require('rxjs/Rx');
var observable = Rx.Observable.of(1,2,3);
var sub = observable.subscribe(console.log);
var sub1 = observable.subscribe(console.log);
它输出 1 2 3 1 2 3(省略新行)。
但是,正如RxJs的文档所说,Observable是一个stream,为什么第二个订阅就拿到了所有的值呢?我的理解是,在第一次订阅之后,observable 已经完成并且作为一个流,它不应该产生它已经发出的值。
我是不是误会了什么?
根据上面引用的文章,Hot vs Cold Observables
Observables are just functions! Observables are functions that tie an observer to a producer. That’s it. They don’t necessarily set up the producer, they just set up an observer to listen to the producer, and generally return a teardown mechanism to remove that listener. The act of subscription is the act of “calling” the observable like a function, and passing it an observer.
因此,observable 只是生产者和观察者之间的管道,生产者可以(通常)拥有状态 'baked in'。
试图证明在你的例子中某处有一个生产者 Rx.Observable.of(1,2,3)
有点困难。
Observable.of 的来源是
export const of = ArrayObservable.of;
和数组Observable.of
static of<T>(...array: Array<T | IScheduler>): Observable<T> {
所以在这种情况下传播运算符是 生产者,array
是传递给 Observable 的状态。
我找不到扩展运算符的源代码,但是这个参考 es6-equivalents-in-es5#spread-operator 给出了以下 es5 等价物
var _toArray = function (arr) {
return Array.isArray(arr) ? arr : [].slice.call(arr);
};
function add(a, b) {
return a + b;
}
var nums = [5, 4];
console.log(add.apply(null, _toArray(nums)));
假设上面的 _toArray()
是价差的合理近似值,我们可以说价差本质上是生产者函数。
那么,Rx.Observable.of(1,2,3)
有状态吗?我们可以说是的,因为该语句包含状态,但等效于
const nums = [1,2,3]
const src = Rx.Observable.of(...nums)
我们可以看到状态实际上是可观察对象的外部。
热的呢?
一个热的可观察对象有一个生产者,它没有按需复制它的值,例如事件。
因此,当生产者很热时,可观察对象不会 'remember' 在管道设置之前状态(即发生订阅时),因此 生产者 的状态不是可观察的。
console.clear()
const eventEmitter = new EventEmitter();
var source = Rx.Observable.fromEvent(eventEmitter, 'data')
eventEmitter.emit('data', 1);
eventEmitter.emit('data', 2);
source.subscribe(x => console.log('subscription', x))
eventEmitter.emit('data', 3);
eventEmitter.emit('data', 4);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.2/Rx.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/EventEmitter/5.2.4/EventEmitter.js"></script>