RxJS5 finalize运算符未被调用。

26

当我所有的可观察对象都执行完成时,我想触发回调。在我的另一个、较老的项目中,我使用了 finally 来实现,效果非常好:

this.myService.callDummy()
  .finally(() => console.log('Works!'))
  .subscribe(result => ...)

但是现在我正在使用一个新版本的 RxJS,其中包含Pipeable operators,但是finally调用(现在改名为finalize)从未被执行。很难找到相关信息,我不确定我做错了什么。

combineLatest(
  this.route.queryParams,
  this.myService.callDummy1(),
  this.myService.callDummy2()
)
.pipe(finalize(() => console.log('Does not work!')))
.subscribe(results => ...);

任何帮助都是受欢迎的。


请在 StackBlitz 上编写一个可工作的代码片段。https://stackblitz.com/fork/angular - Roberto Zvjerković
this.route.queryParams 是什么?很可能是你的某个源 Observable 没有完成。 - martin
@martin,它们都完成了。结果是一个包含3个结果对象的数组,所有结果都符合预期。 - Nico Van Belle
@NicoVanBelle 你能制作一个演示吗? - martin
你误解了“完成”的含义,queryParams可观察对象永远不会完成,所以这是按预期运行的。 - bryan60
3个回答

39

在可观察对象中,触发和完成不是同一件事情。

尽管每个项目都会发出一个值,但根据定义,route.queryParams 永远不会完成,因为 Angular 实现它为一个不终止的可观察对象。您需要手动完成它,以便 finalize 得到执行,因为 combineLatest 仅在其中组合的每个可观察对象都已完成时才会完成。

combineLatest(
  this.route.queryParams.pipe(take(1)), // take(1) will complete the observable after it has emitted one value
  this.myService.callDummy1(),
  this.myService.callDummy2()
)
.pipe(finalize(() => console.log('Does not work!')))
.subscribe(results => ...);

这将完成。


3
从 RxJS 5.5 开始,您不应使用 .take()(修补原型),而应该使用 .pipe(take()) - Mick
2
最终,take(1) 起了作用,但我还将 combineLatest 替换为 forkJoin,因为它的功能被 take 所代替,并且它期望 observables 完成。这样做,更容易调试并查看哪些 observables 尚未完成。 - Nico Van Belle
@NicoVanBelle 当我期望我的 observables 在发出 1 次后就完成时,我更喜欢使用 forkJoin;而当我期望它们持续发出时,则使用 combineLatest。这样更明确地表达了正在发生的事情。 - bryan60
@Mick 我知道这两个答案基本上是一样的,所以我只能接受在我自己看来最有帮助的答案。我不能接受两个答案。话虽如此,我已经给你的答案点了赞,并感谢你提供的帮助。 - Nico Van Belle
你是否考虑过回答问题时不尽可能详细?如果看到错误,也不给出额外的提示? - Mick
显示剩余4条评论

1

你确定其中一个合并的Observable会完成吗?使用.complete.error中的任意一个?

如果没有任何一个合并的Observable完成,finally将永远不会被调用。


是的,它们都完成了。这段代码唯一的问题是 finalize 不起作用。 - Nico Van Belle
this.route.queryParams 未完成。 - Mick
1
正如 @Mick 所提到的,它们返回了值,但实际上并没有完成。我错误地认为它们已经完成了,因为我正在使用 combineLatest,但事实并非如此;当使用它时,这些 observables 不必完成。 - Nico Van Belle

0
如果您想在可观察对象完成时执行某些操作,请使用 complete 回调而不是 finally/finalize:
.subscribe(
    value => { console.log(`Next: ${value}`); },
    error => { console.log(`Error: ${error}`); },
    ()    => { console.log(`Completed`); }
);

无论如何,finally/finalize也应该起作用,并且将在出现错误或完成时调用。我非常确定你的observable永远不会完成。您可以使用上面的代码来确认这一点。

我看到您正在使用Angular并订阅this.route.queryParams,它永远不会完成。您可以通过使用first()创建一个新的observable,以便立即获取值并完成:this.route.queryParams.pipe(first())


5
只有成功载荷响应并返回“value”时,这才有效。如果返回了“error”,则无效。 - sktwentysix

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接