我试图理解为什么如果源{Observable}是用share而不是range创建的,那么timer 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
应该将冷观测变成热的。
此行为背后的解释是什么?
答案 0 :(得分:2)
有两点要指出。
首先,如果仔细查看range
的函数签名,您会看到它带有第三个参数,即SchedulerLike
。
如果未指定,则RxJS立即使用可见的next
的相关值调用每个订户的range
处理程序,直到用尽为止。如果您打算使用share
运算符,那么这是不希望的,因为它有效地绕过了可能引入的任何共享副作用处理。
Relevant snippet taken from the actual implementation:
// src/internal/observable/range.ts#L53
do {
if (index++ >= count) {
subscriber.complete();
break;
}
subscriber.next(current++);
if (subscriber.closed) {
break;
}
} while (true);
timer
也采用可选的SchedulerLike
参数。如果未指定,则该实现默认采用AsyncScheduler
,与range
的默认设置不同。
第二,share
运算符应遵循所有可能有副作用的其他运算符。如果先于它们,则管道操作员处理的预期统一行为将丢失。
因此,请牢记两点,使share
运算符与range
一起使用:
const { asyncScheduler, range, timer } = rxjs;
const { mapTo, tap, share } = rxjs.operators;
// Pass in an `AsyncScheduler` to prevent immediate `next` handler calls
const source = range(1, 1, asyncScheduler).pipe(
tap(() => console.log('***SIDE EFFECT***')),
mapTo('***RESULT***'),
// All preceding operators will be in shared processing
share(),
);
const sub3 = source.subscribe(console.log);
const sub4 = source.subscribe(console.log);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.4.0/rxjs.umd.min.js"></script>