我正在编写一个游戏,角色可以在其中射击武器。
我希望玩家尝试射击时会发生不同的事情,这取决于他们是否有弹药。
我将问题归结为以下代码(顺便说一句,我不确定为什么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"
),这很有意义,因为hasAmmo
是true
。但是,由于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()
在这里无效。如果要共享它,则必须在from
和fire$
上使用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/