Rxjs shareReplay

1,373 阅读2分钟

共享源并在订阅时重播指定数量的发出。

构造函数

shareReplay<T>(configOrBufferSize?: number | ShareReplayConfig, windowTime?: number, scheduler?: SchedulerLike): MonoTypeOperatorFunction<T>

参数

参数说明
configOrBufferSize可选。默认为undefined
类型:number | ShareReplayConfig
windowTime可选。默认为undefined
重播缓冲区的最大时间长度(毫秒)。
scheduler可选。默认为undefined
调度程序,选择器函数中连接的观察程序将在其中调用。

返回

MonoTypeOperatorFunction<T>: 返回一个Observable序列的函数,包含在选择器函数中对源序列进行多播产生的序列元素。

描述

这个操作符是replay的一个专门化,它通过一个用指定参数构造的ReplaySubject连接到一个可观察的源和多播。成功完成的源将永远缓存在shareReplayed observable中,但出错的源可以重试。

为什么要使用shareReplay

当你不希望在多个subscribers之间执行副作用或繁重的计算时,通常希望使用shareReplay。它也可能很有用的,当你知道你将有对于一个流的延迟的订阅者需要访问先前提交的值。这种在订阅上重播值的能力是shareshareReplay的区别。

参考计数

从RXJS版本6.4.0开始,添加了一个新的重载签名,以允许手动控制当操作员内部参考计数器降为零时发生的情况。如果refCount为true,则一旦引用计数降至零,源将取消订阅,即内部ReplaySubject将取消订阅。所有新的订户都将从一个新的ReplaySubject接收值发射,这反过来又将导致对可观测源的新订阅。另一方面,如果refCount为false,则源将不会取消订阅,这意味着内部ReplaySubject仍将订阅源(并且可能永远运行)。

例如:

import { interval } from 'rxjs';
import { shareReplay, take } from 'rxjs/operators';

const obs$ = interval(1000);
const shared$ = obs$.pipe(
  take(4),
  shareReplay(3)
);
shared$.subscribe(x => console.log('sub A: ', x));
shared$.subscribe(y => console.log('sub B: ', y));

refCount使用的例子:

import { interval, Observable, defer } from 'rxjs';
import { shareReplay, take, tap, finalize } from 'rxjs/operators';

const log = <T>(source: Observable<T>, name: string) => defer(() => {
  console.log(`${name}: subscribed`);
  return source.pipe(
    tap({
      next: value => console.log(`${name}: ${value}`),
      complete: () => console.log(`${name}: complete`)
    }),
    finalize(() => console.log(`${name}: unsubscribed`))
  );
});

const obs$ = log(interval(1000), 'source');

const shared$ = log(obs$.pipe(
  shareReplay({bufferSize: 1, refCount: true }),
  take(2),
), 'shared');

shared$.subscribe(x => console.log('sub A: ', x));
shared$.subscribe(y => console.log('sub B: ', y));

// PRINTS:
// shared: subscribed <-- reference count = 1
// source: subscribed
// shared: subscribed <-- reference count = 2
// source: 0
// shared: 0
// sub A: 0
// shared: 0
// sub B: 0
// source: 1
// shared: 1
// sub A: 1
// shared: complete <-- take(2) completes the subscription for sub A
// shared: unsubscribed <-- reference count = 1
// shared: 1
// sub B: 1
// shared: complete <-- take(2) completes the subscription for sub B
// shared: unsubscribed <-- reference count = 0
// source: unsubscribed <-- replaySubject unsubscribes from source observable because the reference count dropped to 0 and refCount is true

// In case of refCount being false, the unsubscribe is never called on the source and the source would keep on emitting, even if no subscribers
// are listening.
// source: 2
// source: 3
// source: 4
// ...