RxJs共享运算符和使用范围创建的可观察对象

RxJs共享运算符和使用范围创建的可观察对象,rxjs,reactive-programming,Rxjs,Reactive Programming,我试图理解为什么RxJs操作符的工作方式不同,如果源可观察对象是使用而不是创建的 将原始代码更改为: const source = range(1, 1) .pipe( share() ) const example = source.pipe( tap(() => console.log('***SIDE EFFECT***')), mapTo('***RESULT***'), ) const sharedExample = examp

我试图理解为什么RxJs操作符的工作方式不同,如果源可观察对象是使用而不是创建的

将原始代码更改为:

const source = range(1, 1)
    .pipe(
        share()
    )

const example = source.pipe(
    tap(() => console.log('***SIDE EFFECT***')),
    mapTo('***RESULT***'),
)

const sharedExample = example
const subscribeThree = sharedExample.subscribe(val => console.log(val))
const subscribeFour = sharedExample.subscribe(val => console.log(val))
结果:

console.log src/pipeline/foo.spec.ts:223 副作用

console.log src/pipeline/foo.spec.ts:228 结果

console.log src/pipeline/foo.spec.ts:223 副作用

console.log src/pipeline/foo.spec.ts:229 结果

基本上,副作用会被多次调用

据我所知,
range
被认为是一个冷的可观测值,但据说
share
应该将冷的可观测值变成热的


这种行为背后的解释是什么?

有两点需要指出

首先,如果仔细查看
范围
的函数签名,您会发现它使用了第三个参数,一个类似于
调度的

如果未指定,RxJS会立即调用每个订阅者的
next
处理程序,并使用
范围的相关值
进行观察,直到其耗尽。如果您打算使用
share
操作符,这是不可取的,因为它有效地绕过了可能引入的任何共享副作用处理

//src/internal/observable/range.ts#L53
做{
如果(索引+>=计数){
subscriber.complete();
打破
}
subscriber.next(当前++);
if(订阅服务器关闭){
打破
}
}虽然(正确);
timer
还采用可选的
SchedulerLike
参数。如果未指定,则实现默认采用不同于
范围的默认值

其次,
share
操作符应该遵循所有其他可能有副作用的操作符。如果在它们之前,管道操作符处理的预期统一行为将丢失

因此,牢记这两点,要使
share
操作符按照您的预期使用
range

const{asyncScheduler,range,timer}=rxjs;
const{mapTo,tap,share}=rxjs.operators;
//传入“AsyncScheduler”以防止立即调用“next”处理程序
常量源=范围(1,1,异步调度器)。管道(
轻触(()=>console.log('***副作用***'),
映射到(“***结果***”),
//所有前面的运算符都将处于共享处理中
share(),
);
const sub3=source.subscribe(console.log);
const sub4=source.subscribe(console.log)

那么,一般的结论是
share
只适用于异步调度的可观察对象吗?如果不提供调度器,我也无法将其转换为
ConnectableObservable
,对吗?是否有一种方法可以同步实现这一点(创建observable、1st subscribe、2nd subscribe和blocking调用以开始生成事件)。@dev null,是的,但如果有疑问,我建议您检查所使用的observable Generation操作符的底层实现是否与默认使用的调度程序有任何细微差别。请注意,如果将调度程序替换为
QueueScheduler
(文档将其描述为同步行为),则也不会得到预期的行为。