【问题标题】:Why RxJS function toPromise is not unsubscribing from subscription为什么 RxJS 函数 toPromise 没有取消订阅
【发布时间】:2025-12-04 11:15:02
【问题描述】:

在我们的应用中,我们使用的地方很多:

someObservable.take(1).subscribe(onSuccessHandler, onFailureHandler);

但是对于订阅,您需要担心在某些时候取消订阅,这并不总是那么简单。

我正在考虑将其简化并将其重写为:

someObservable.toPromise().then(onSuccessHandler).catch(onFailureHandler);

但是查看toPromise() (here) 的实现,我似乎不明白为什么它不关心退订。

代码中的注释说不能取消,但是我们如何让它这样泄漏内存(如果我们真的是这样的话)。

编辑

我想出了一个让我担心的例子:

Observable.timer(10, 10).toPromise().then((v) => console.log("I'm done"));

如果我检索到的 observables 永远不会完成,那么不仅我的 promise 永远不会以一个值完成,而且我也无法取消订阅这些 observables(例如超时它们和我的 promise),因为我有无权访问订阅对象。这确实会泄漏内存!

【问题讨论】:

    标签: javascript promise rxjs observable


    【解决方案1】:

    我的猜测是,这是因为一个 Promise 只被解析一次(不像是一个流的序列)。请注意,订阅者始终保留最新值,失败时拒绝并在完成时解析为最新值。

    要亲自尝试,请尝试:

        Observable.timer(300,300).take(4).toPromise().then((v) => console.log('tick: ', v)); // logs "3", the last element
        Observable.from(['a','b','c']).toPromise().then((v) => console.log('tick: ', v)); // logs "c", the last element
    

    至于取消订阅,它在完成时是自动的,所以在完成之前,你不应该取消订阅,在完成时,你解决了承诺并默默地(由于 observables 的默认行为)取消订阅。

    【讨论】:

      【解决方案2】:

      'No cancel can be done' 评论可能是指取消承诺,这与可观察到的完成完全不同。关于那个操作符的实现,你会发现如果你仔细观察,.subscribe 是用它的三个参数调用的:

      • onNext 处理程序,用于保存流式传输的值
      • 拒绝承诺的 onError 处理程序
      • 完成处理程序,用持有的值解决承诺

      然后 Rxjs 流的工作原理是,当一个流完成时,会发生一个自动取消订阅链,就像订阅一个流时,会发生一个自动订阅链一样。

      更多信息请看here

      【讨论】: