RxJ共享运算符,并创建带有范围的Observable

时间:2019-02-09 14:17:12

标签: rxjs reactive-programming

我试图理解为什么如果源{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应该将冷观测变成热的。

此行为背后的解释是什么?

1 个答案:

答案 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>