为什么 RxJS 中 Finalize 被解除?

kre*_*erd 6 rxjs

我无法理解RxJS 中的Finalize运算符。让我用一个例子来演示这一点:

of(null).pipe(
  tap({ complete: () => console.log('tap 1 completes') }),
  finalize(() => console.log('finalize')),
  tap({ complete: () => console.log('tap 2 completes') })
).subscribe({ complete: () => console.log('subscribe completes') });
Run Code Online (Sandbox Code Playgroud)

我希望finalize回调在第二个之前执行tap。但这并没有发生。相反,上面的代码会产生以下输出:

tap 1 completes
tap 2 completes
subscribe completes
finalize
Run Code Online (Sandbox Code Playgroud)

看看实现,相信操作符通过整个可观察链传递(提升),以便始终在其末端应用。所以现在我有两个问题:

  1. 这个设计决策背后的理由是什么?您能否解释一下为什么这是一个理想/有利的财产?
  2. 是否有不同的运算符或其他解决方案来在完成和出错时执行代码,但按顺序(即在上面示例中的第二个之前tap)而不是在可观察链的末尾?

mar*_*tin 8

重要的是要意识到这一点finalize()tap()以截然不同的方式工作。由和通知tap()触发next,而仅在链 ubsubscription 上触发。换句话说,与使用非常相似:errorcompletefinalize()finalize()

const subscription = $source.subscribe();
// This will be always triggered after all `tap()`s
subscription.add(() => console.log('same as finalize()'));
Run Code Online (Sandbox Code Playgroud)

所以你不能finalize()在之前调用tap()。另外,请注意,finalize()当您手动取消订阅以下内容时,也会调用该方法:

subscription.unsubscribe(); // will always invoke `finalize()` but never `tap()`
Run Code Online (Sandbox Code Playgroud)

一种可能的解决方案是实现您自己的finalize()变体,该变体知道它被调用的原因: https: //github.com/martinsik/rxjs-extra/blob/master/doc/finalizeWithReason.md (请参阅源代码)

另请注意,https ://github.com/ReactiveX/rxjs/pull/5433对您的用例没有影响。