我正在编写一个游戏,角色可以在其中射击武器。
我希望玩家尝试射击时会发生不同的事情,这取决于他们是否有弹药。

我将问题归结为以下代码(顺便说一句,我不确定为什么SO的摘要功能不起作用,所以我做了CodePen,可以在这里尝试我的代码)。



const { from, merge } = rxjs;
const { partition, share, tap } = rxjs.operators;

let hasAmmo = true;
const [ fire$, noAmmo$ ] = from([true]).pipe(
  share(),
  partition(() => hasAmmo),
);


merge(
  fire$.pipe(
    tap(() => {
      hasAmmo = false;
      console.log('boom');
    }),
  ),
  noAmmo$.pipe(
    tap(() => {
      console.log('bam');
    }),
  )
).subscribe({
  next: val => console.log('next', val),
  error: val => console.log('error', val),
  complete: val => console.log('complete', val),
});

<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.3.3/rxjs.umd.js"></script>





运行此代码时,我得到以下信息:

"boom"
"next" true
"bam"
"next" true
"complete" undefined


我不明白为什么会得到"bam"

第一个发射到fire$(我得到一个"boom"),这很有意义,因为hasAmmotrue。但是,由于fire$发出的副作用是分区条件的结果发生了变化,我想这使我得到了"bam"

我不应该引起影响partition()的副作用吗?

也许我share()父母可观察的方式有问题吗?我可能是错的,但我会凭直觉认为fire$noAmmo$在内部订阅父对象以进行拆分,在这种情况下share()应该可以工作?

最佳答案

它实际上可以正常工作。混淆来自partition运算符,该运算符基本上只是two filter operators

如果不使用partition重写它,则它看起来像这样:

const fire$ = from([true]).pipe(
  share(),
  filter(() => hasAmmo),
);

const noAmmo$ = from([true]).pipe(
  share(),
  filter(() => !hasAmmo),
);


请注意,更改hasAmmo不会影响partition本身。 partition仅在从其源Observable接收值时起作用。

以后使用merge()时,它将对具有两个不同from([true])的两个完全不同的链进行两个单独的预订。这意味着true传递给fire$noAmmo$

因此,share()在这里无效。如果要共享它,则必须在fromfire$上使用noAmmo$进行包装。如果源Observable仅是from,那么它将变得更加混乱,因为初始发射只会到达第一个订阅者,而第一个订阅者后来在fire$中使用时是merge

const shared$ = from([true]).pipe(
  share(),
);

const fire$ = shared$.pipe(...);
const noAmmo$ = shared$.pipe(...);


您同时收到两条消息的最后一件事是partition不会修改通过的值。它仅决定返回的Observable中的哪一个将重新发送它。

顺便说一句,而不是完全避免使用partition,因为它可能会被弃用,而只需使用filter,这会更加明显:


https://github.com/ReactiveX/rxjs/issues/3797
https://github.com/ReactiveX/rxjs/issues/3807

关于javascript - RxJS在分区子可观察对象之间共享父可观察对象,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53106634/

10-12 15:57