为什么在RxJS中使用finalize?
我无法理解RxJS中的运算符。让我用一个例子来说明这一点:为什么在RxJS中使用finalize?,rxjs,Rxjs,我无法理解RxJS中的运算符。让我用一个例子来说明这一点: of(null).pipe( tap({ complete: () => console.log('tap 1 completes') }), finalize(() => console.log('finalize')), tap({ complete: () => console.log('tap 2 completes') }) ).subscribe({ complete: () => con
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') });
我希望在第二次点击之前执行finalize
回调。但这并没有发生。相反,上述代码生成以下输出:
tap 1 completes
tap 2 completes
subscribe completes
finalize
从这个角度来看,我相信算符是通过(提升)整个可观察链的,始终应用在它的末端。现在我有两个问题:
这个设计决策背后的基本原理是什么?你能解释一下为什么这是一个理想的/有利的财产吗
是否有不同的操作员或其他解决方案在完成和出错时按顺序(即在上例中的第二次点击之前)而不是在可观察链的末端执行代码
这就是finalize
操作符的全部原理。仅在源可观测完成后发射。这意味着,在处理完所有完整的订阅后,计算tap
complete。从文档中:
返回一个Observable,该Observable镜像源Observable,但当源在完成或出错时终止时将调用指定函数
现在您可以将finalize
放在一个内部可观察对象中,但我想您也不会喜欢这样的顺序
of(null).pipe(
tap({ complete: () => console.log('tap 1 completes') }),
concatMap((resp) => of(resp).pipe(
finalize(() => console.log('finalize'))
)),
tap({ complete: () => console.log('tap 2 completes') })
).subscribe({ complete: () => console.log('subscribe completes') });
这将使finalize
在第一次和最后一次点击之前执行,这是因为传递到tap
的complete
对象。如果您只需在第一个点击中传入一个函数,它将具有正确的顺序
另一种方法是使用concat
:
concat(
of(null).pipe(
tap({complete: () => console.log('tap 1 completes' ) }),
finalize(() => console.log('finalize'))
),
EMPTY.pipe(
tap({complete: () => console.log('tap 2 completes' ) })
)
).subscribe({ complete: () => console.log('subscribe completes') });
但这会阻止你访问第一个可观测到的发射物。因此,基本上,我认为没有一个合适的解决方案来解决您的问题:)重要的是要知道,finalize()
和tap()
的工作方式非常不同tap()
由next
、error
和complete
通知触发,而finalize()
仅在链订阅时触发。换句话说,finalize()
非常类似于使用:
const subscription = $source.subscribe();
// This will be always triggered after all `tap()`s
subscription.add(() => console.log('same as finalize()'));
因此,您不能在点击()之前调用finalize()
。另外,请注意,手动取消订阅liek时也会调用finalize()
:
subscription.unsubscribe(); // will always invoke `finalize()` but never `tap()`
一种可能的解决方案是实现您自己的finalize()
变量,该变量知道调用它的原因:
另外请注意,这对您的用例没有影响。有趣!到目前为止,我认为finalize
相当于Promise.finally
。显然,这里还有更多的事情要做。谢谢你的建议!现在我想我实际上是在搜索tap
的变体,而不是finalize
的变体。我想我可以自己定义:const-tapOnEnd=callback=>tap({complete:()=>callback(),error:()=>callback()})
@kremerd我有点确定finalize
也会在那之后被调用。你是对的。我的意思是用它代替finalize
操作符,而不是代替另一个tap
s。这样,执行顺序应该是直接的,因为它只是处理一系列的tap
s。我忘记了,当出现可观察到的错误时,它也会调用complete
。如果希望这些函数相同,只需使用complete
。检查(我已经实现了您的tapOnEnd
),我认为在出现错误时不会调用complete
。我也在a中尝试过,只调用了error
回调。也许我错过了什么。“此处”链接已断开,因此我无法检查您的实现。