为什么在此setTimeout()示例中rxjs共享运算符不能按预期工作?

时间:2019-10-11 09:11:26

标签: javascript typescript rxjs

我不明白为什么rxjs共享运算符不能与setTimeout()一起使用。

我正在尝试了解此blogpost。在此示例中,“共享订阅”的概念似乎没有按预期工作。

const observable1 = Observable.create(observer => {
  observer.next(`I am alive.`);
  setTimeout(() => {
    observer.next(`I am alive again.`);
  }, 1000);
}).pipe(share());

observable1.subscribe(x => console.log(x));
observable1.subscribe(x => console.log(x));

预期:

I am alive.
I am alive again.

实际:

I am alive.
I am alive again.
I am alive again.

Reproducable stackblitz.

2 个答案:

答案 0 :(得分:4)

这是预期的输出。

摘自share()运算符上的官方文档:

  

返回一个新的Observable,它多播(共享)原始Observable。只要有至少一个订户,该Observable便会被预订并发出数据。

这意味着观察者一订阅,可观察对象就开始发射数据。

因此,当第一个订阅语句observable1.subscribe(x => console.log(x));执行时,观察者将进行订阅,并且observer.next('I am alive.);语句会发出数据。

当第二个订阅语句执行时,另一个观察者进行订阅,并且它仅接收从该时间点发出的数据。这是observer.next('I am alive again.');setTimeout()方法发出的数据。

我们可以在此StackBlitz demo中清楚地看到这一点,在其中记录Observer1Observer2文本以及接收到的数据。

我认为混淆点在于看到两个I am alive again.语句。 它被记录了两次,因为我们正在每个订户中对其进行记录。将这些日志语句移至可观察的位置,它们将仅记录一次。这使得可观察对象只执行一次。

答案 1 :(得分:1)

这是share()的假定行为。它仅监视和共享一个动作。这是一个来自learningrxjs.com的示例。如您所见,仅监视tap()运算符。 mapTo()运算符将被忽略。

// RxJS v6+
import { timer } from 'rxjs';
import { tap, mapTo, share } from 'rxjs/operators';

//emit value in 1s
const source = timer(1000);
//log side effect, emit result
const example = source.pipe(
   tap(() => console.log('***SIDE EFFECT***')),
   mapTo('***RESULT***')
);

/*
  ***NOT SHARED, SIDE EFFECT WILL BE EXECUTED        
 TWICE***
  output:
  "***SIDE EFFECT***"
  "***RESULT***"
  "***SIDE EFFECT***"
  "***RESULT***"
*/
const subscribe = example.subscribe(val => console.log(val));
const subscribeTwo = example.subscribe(val => console.log(val));

//share observable among subscribers
const sharedExample = example.pipe(share());
/*
  ***SHARED, SIDE EFFECT EXECUTED ONCE***
  output:
  "***SIDE EFFECT***"
  "***RESULT***"
  "***RESULT***"
*/
const subscribeThree = sharedExample.subscribe(val => console.log(val));
const subscribeFour = sharedExample.subscribe(val => console.log(val));