为什么没有shareReplay()的两个可观察对象的订阅都不会执行两次代码?

时间:2019-07-10 18:39:51

标签: javascript angular typescript rxjs observable

我试图找出RxJ。特别是ShareReplay运算符。根据我的理解,如果对一个可观察对象有两个订阅,那么该可观察对象应该执行两次。除非涉及到shareReplay。显然我的理解是错误的,因为这不是我在这里发生的事情。有人可以帮我理解吗?

export class TestComponent implements OnInit {
      constructor() {}
      i = 0;
      ngOnInit() {
        console.clear();
        let ob = this.httpcall().pipe(map(d => d));
        let ob1$ = ob.pipe(map(d => d.toUpperCase()));
        let ob2$ = ob.pipe(map(d => d.toLowerCase()));

        ob1$.subscribe(d => {
          console.log(d);
        });
        ob2$.subscribe(d => {
          console.log(d);
        });
      }

      httpcall() {
        console.log("called");
        this.i++;
        return of("server cAlled:" + this.i);
      }
    }

输出:

called
 SERVER CALLED:1
 server called:1

即使有两个订阅并且不涉及shareReplay,我的计数器也没有增加到两个。

我期望(没有shareReplay):

 called
 SERVER CALLED:1
 called
 server called:2

并且我期望使用let ob = this.httpcall().pipe(map(d=>d),shareReplay());

 called
 SERVER CALLED:1
 server called:1

3 个答案:

答案 0 :(得分:2)

当您调用订阅时,这将导致可观察对象执行其定义要执行的所有操作。它是使用of("server cAlled: 1");定义的,然后将其传递给地图运算符。因此,由于您订阅了两次,因此of会做两次,而map会做两次。

您碰巧在名为httpcall的函数中创建了可观察对象,但是该可观察对象对httpcall一无所知。 httpcall将不会再被调用。

如果您希望this.i的增量成为预订时发生的事情的一部分,则可能需要使用Observable.create。例如:

httpcall() {
  return Observable.create((observer) => {
    this.i++;
    observer.next("server called: " + this.i);
    observer.complete();
  })
}

答案 1 :(得分:0)

似乎return observable是它自己的,所以它的主体不会被执行两次,因此我重新创建了示例以显示正常observable和of之间的区别

export class AppComponent implements OnInit {
  constructor(
  ) {
  }

  i = 0;

  ngOnInit() {
    console.clear();
    const ob = this.httpCall1();
    const ob1$ = ob.pipe(map(d => d.toUpperCase()));
    const ob2$ = ob.pipe(map(d => d.toLowerCase()));

    ob1$.subscribe(d => {
      console.log(d);
    });
    ob2$.subscribe(d => {
      console.log(d);
    });

    this.i = 0;

    const ob2 = this.httpCall2();
    const ob3$ = ob2.pipe(map(d => d.toUpperCase()));
    const ob4$ = ob2.pipe(map(d => d.toLowerCase()));

    ob3$.subscribe(d => {
      console.log(d);
    });
    ob4$.subscribe(d => {
      console.log(d);
    });
  }

  httpCall1() {
    return of('server1 called:' + ++this.i).pipe(
      tap(d => console.log('tap1', d)),
    );
  }

  httpCall2() {
    return new Observable<string>((observer) => {
      this.i++;
      observer.next('server2 called: ' + this.i);
      observer.complete();
    }).pipe(
      tap(d => console.log('tap2', d)),
    );
  }

}

答案 2 :(得分:0)

这是因为httpcall()仅通过以下行let ob = this.httpcall().pipe(map(d => d));被调用一次。因此,这意味着Observable返回的httpcall()随后将被重用。

如果可以的话,现在考虑一下ob,它是源可观察的。如果您订阅此Observable,您将获得of("server cAlled:" + this.i);,其中this.i = 1。如果再次执行方法this.ihttpcall()只会增加,但不会。 相反,您正在订购冷的Observable ob,它将仅打印用于创建它的内容。 this.i的值(等于1)已经存储在Observable内部ob,并且无论您订阅ob有多少次,在创建新实例之前都不会更改它。


现在让我们看一下下面的不同代码:

    let ob1$ = this.httpcall().pipe(map(d => d)).pipe(map(d => d.toUpperCase()));
    let ob2$ = this.httpcall().pipe(map(d => d)).pipe(map(d => d.toLowerCase()));

在这种情况下,httpcall()被两次调用,因此this.i++;将会发生两次,并且您将获得想要的结果。