Rxjs 为什么使用共享会阻止可观察的使用withLatestFrom?
问题 我有以下操作员:Rxjs 为什么使用共享会阻止可观察的使用withLatestFrom?,rxjs,Rxjs,问题 我有以下操作员: const prepare = (value$: Observable<string>) => value$.pipe( tap((x) => console.log("prepare: ", x)), share() ); const performTaskA = (removed$: Observable<string>) => removed$.p
const prepare = (value$: Observable<string>) =>
value$.pipe(
tap((x) => console.log("prepare: ", x)),
share()
);
const performTaskA = (removed$: Observable<string>) =>
removed$.pipe(tap((x) => console.log("taskA: ", x)));
const performTaskB = (removed$: Observable<string>) =>
removed$.pipe(
tap((x) => console.log("taskB 1: ", x)),
withLatestFrom(otherValue$),
tap((x) => console.log("taskB 2: ", x))
);
产生以下输出:
prepare: TEST
taskA: TEST
taskB 1: TEST
请注意,taskb2
未被记录-在performTaskB
中,taskBDone
可观察到的已在与最新自(其他值$)
处暂停
如果prepare
中的share
被删除,则可观察对象不会暂停,但它(毫不奇怪)会导致prepare
执行两次,这是我不希望看到的
问题
如何执行performTaskA
和performTaskB
但prepare
只能执行一次
根据下面的调试说明,share
为什么会导致发射序列的更改
演示
有股份(如上所述):
无股份:
转到右侧的测试选项卡,确保控制台可见,然后单击播放按钮
部分解释
使用LatestFrom调试,很明显,当源(已删除$
)发射时,就绪
为假
,这会阻止发射
出现这种情况的原因是,当存在share
时,输入(otherValue$
)订阅在源之后发出,因此尚未设置ready
。(或者是share
导致源更早发射的原因?)
但是当share
被删除时,输入订阅会在源代码之前发出,这意味着ready
通过and设置为true,因此withLatestFrom
会按预期发出。我尝试运行您的代码,但无法像您的代码那样将其挂起。我怀疑这与您的测试框架如何管理可观察性有关。我无法复制它
我确实注意到,您所写的内容中存在一些固有的交错/排序问题。共享同步观测值会带来一些问题,例如第一个观测者同步观测所有源值,并在第二个观测者订阅之前完成观测。即使它们应该“同时”订阅,也会发生这种情况
使用事件循环进行排序
我在这里写的东西对我很有用:
函数初始化(
价值$:可观察到,
otherValue$:可观察
) {
常量准备=管道(
轻触(x=>console.log(“准备:,x)),
延迟(0),
股份()
);
const performTaskA=管道(
轻触(x=>console.log(“taskA:,x))
);
const performTaskB=管道(
点击(x=>console.log(“taskb1:,x)),
withLatestFrom(otherValue$),
点击(x=>console.log(“taskb2:,x))
);
const prepared$=值$.pipe(prepare);
合并(
准备好的美元管道(performTaskA),
已准备的美元管道(performTaskB)
).subscribe();
}
初始(属于(“a”)、属于(“b”);
对我来说,这会将其打印到控制台:
prepare:a
taskA:a
任务B 1:a
任务b 2:[“a”、“b”]
您将注意到在prepare
中调用delay(0)。如果不这样做,则会调用prepare两次,因为共享的可观察对象已同步完成。延迟(0)只是尽快将下一个调用放入事件队列
这不是最好的解决办法。这是一个黑客。最佳解决方案取决于如何使用。大多数情况下,shareReplay(1)完成了这项工作。如果你在这里用,那就行了
使用发布/连接进行订购
否则,您可以发布并连接,以确保订单符合预期
发布/连接允许您在源正式启动/连接/订阅之前设置对源的所有订阅。这确保了在任何事情发生之前,所有回调和恢复都已就绪。这是确保完全同步的可观察对象可以共享其值的唯一方法
函数初始化(
价值$:可观察到,
otherValue$:可观察
) {
常量准备=管道(
轻触(x=>console.log(“准备:,x)),
股份()
);
const performTaskA=管道(
轻触(x=>console.log(“taskA:,x))
);
const performTaskB=管道(
点击(x=>console.log(“taskb1:,x)),
withLatestFrom(otherValue$),
点击(x=>console.log(“taskb2:,x))
);
const prepared$=publish()(值$.pipe(prepare));
合并(
准备好的美元管道(performTaskA),
已准备的美元管道(performTaskB)
).subscribe();
已准备好$.connect();
}
在performTaskB
中,您直接在中使用值$
,而不是prepare
返回的共享版本。但是removed$
参数实际上是共享的value$
,因此我们在这个函数中使用了两个不同版本的value$
。这是故意的吗?这是故意的,因为它显示了我的问题。不过,我已经编辑了这个问题,因此现在withLatestFrom
引用了一个单独的变量,该变量更接近我的真实示例,并且仍然显示了这个问题。谢谢-我认为解释可能与您今天的另一个问题相似,但不完全相同。在本例中,您传递的“测试”可观测值(以及otherValue$
)是什么?我通过TestScheduler
/marbles将它们作为冷可观测值传递-请参见-这有点像我的真实世界应用程序,value$
是主题
,并且$otherValue
连接到ngrx选择器。不管怎样,我在这里和我的应用程序中都有同样的问题。谢谢。@backtick我已经深入研究了这个问题,并相应地更新了这个问题。非常感谢您的回答,并对延迟回复表示歉意。我很欣赏这个解释,但是第一个解决方案并不代表我的场景(其中输入观察值不完整),第二个解决方案仍然显示出与我最初遇到的问题相同的问题-请参见-从右侧的测试选项卡运行测试,并观察右下角的控制台输出。我说我有
prepare: TEST
taskA: TEST
taskB 1: TEST