为什么RxJS中的mergeMap在不是ReplaySubject时会记住历史

为什么RxJS中的mergeMap在不是ReplaySubject时会记住历史,rxjs,Rxjs,屏幕上的两个按钮,点击像这样插入 b1c: number; b1s: Subject<number>; o1: Observable<number>; b2c: number; b2s: Subject<number>; o2: Observable<number>; rxjs(): void { this.b1c = 0; this.b1s = new Subject<number>()

屏幕上的两个按钮,点击像这样插入

  b1c: number;
  b1s: Subject<number>;
  o1: Observable<number>;
  b2c: number;
  b2s: Subject<number>;
  o2: Observable<number>;


  rxjs(): void {
    this.b1c = 0;
    this.b1s = new Subject<number>()

    this.b2c = 0;
    this.b2s = new Subject<number>()

    this.b1s.pipe(
      tap (z => console.log('do', z)),
      mergeMap(z1 => this.b2s.pipe(
        map(z2 => `${z1} / ${z2}`)
      ))
    ).subscribe(z => console.log(z));

    // When you click button 1 nothing happens.
    // When you click button 2 you get output i/j for all values of i from 0 to current, and the current value of j.
    // This is incorrect because this.b1s is not a ReplaySubject and therefore should not remember the previous values.
  }

  buttonClick(buttonNumber: number) {
    if (buttonNumber === 1) {
      this.b1s.next(this.b1c);
      this.b1c++;
    }
    else {
      this.b2s.next(this.b2c);
      this.b2c++;
    }
  }
因为0到4已经被消耗;没有理由要记住它们

事实上,可能根本就不应该有输出,因为在任何时候,两个观察对象都不会同时触发——你不能同时点击两个按钮

您如何解释这种行为,以及如何从文档中推断出这种行为

此外:我不明白为什么会有三个30岁和三个50岁,为什么他们会混淆在一起。应该有六个输出,因为有六个事件。 我们仍然需要记住另一个来源的最后一个价值

到底是什么

10*i--10*i--10*i-|

应该是什么意思?

你所理解的“记住历史”只是主动订阅

obs1.pipemergeMapv=>obs2将源obs1中的每个值映射到流obs2。因此,多个obs2流同时具有活动订阅。这些obs2流合并到一个输出流中,并一直运行,直到它们完成、出错或您取消订阅为止

在您的例子中,obs2=b2s是一个主题,它是一个热的可观察对象,不会自行终止。最终观测值的行为如下所示:

这是B.B.S.管道 mergeMapz1=>this.b2s.pipe mapz2=>`${z1}/${z2}` .subscribebez=>console.logz; b1s:-0-1-2-3-4----5-6-7---- b2s-7:│ │ │ │ │ │ │ └-7/1-- b2s-6:│ │ │ │ │ │ └---6/1-- b2s-5:│ │ │ │ │ └----5/1-- b2s-4:│ │ │ │ └-4/0------4/1-- b2s-3:│ │ │ └---3/0------3/1-- b2s-2:│ │ └----2/0------2/1-- b2s-1:│ └------1/0------1/1-- b2s-0:└-------0/0------0/1-- 输出:------------0/0-------0/1-- 1/0 1/1 2/0 2/1 3/0 3/1 4/0 4/1 5/1 6/1 7/1 b2s发出1时,b2s-0-b2s-4的订阅仍处于活动状态

如果您不希望内部流无限期地运行,您必须以某种方式终止它们。如果只希望它们发出一个值,则可以使用take1

这是B.B.S.管道 mergeMapz1=>this.b2s.pipe take1,/`${z1}/${z2}` .subscribebez=>console.logz; b1s:-0-1-2-3-4----5-6-7---- b2s-7:│ │ │ │ │ │ │ └-7/1| b2s-6:│ │ │ │ │ │ └---6/1| b2s-5:│ │ │ │ │ └----5/1| b2s-4:│ │ │ │ └-4/0| b2s-3:│ │ │ └---3/0| b2s-2:│ │ └----2/0| b2s-1:│ └------1/0| b2s-0:└-------0/0| 输出:------------0/0-------5/1-- 1/0 6/1 2/0 7/1 3/0 4/0 在文档中,obs2=10--10--10-|是一个冷可观测值,在3次发射后终止。它还为每个订阅者产生相同的3次发射,不同于你的拍摄对象

ob1:-1-------3-------5--------------| 表2-3:│ │ └10*5---10*5---10*5-| 表2-2:│ └10*3---10*3---10*3-| 表2-1:└10*1---10*1---10*1-| 输出:--10*1--10*1--10*1--10*3--10*3-10*5-10*3-10*5--10*5--| = -10 --- 10 --- 10 --- 30 --- 30 - 50 - 30 - 50 --- 50 --|
在你的代码中,你有mergeMap,而不是像你在标题中所说的switchMap;虽然switchMap也是完全不可穿透的。每次你点击b1s,你就是在把另一个可观察的东西合并到这个链中。所以当你点击b2s时,你已经将b2s合并了5次,所以它将产生5次排放。这正是它的工作原理。它将最近从b1s激发的值合并为一系列从b2s激发的值,这些值被mergeMap记住。第一次点击按钮1没有做任何事情,因为b2s还没有触发任何东西。它与Replay Subject或Behavior Subject无关。关于大理石语法,每次单击b2,b1都会回放其整个历史。为什么?这完全出乎意料。当两个流都有非空的历史记录时,为什么单击b1不输出任何内容?假设当前值为b1:10和b2:100。然后单击b1应输出11/100,单击b2应输出10/101。@RichardBarraclough b1不会重放其历史记录。b1发出时,此值被映射到b2.pipemapz2=>'${z1}/${z2}'。这将导致订阅b2.pipemapz2=>'${z1}/${z2}',但此内部可观察对象不会直接发出任何信息,因为b2不会重放其历史记录。因此,您最终得到了对b2.pipemapz2=>'${z1}/${z2}'的多个订阅,订阅次数与b1发出的次数相同。当b2发出b2.pipemapz2=>'${z1}/${z2} '发射。因此,对于b2.pipemapz2=>'${z1}/${z2}'的每个活动订阅,您都会得到一个输出。
10*i--10*i--10*i-|