Subject.complete() 是不是取消订阅所有听众?

Posted

技术标签:

【中文标题】Subject.complete() 是不是取消订阅所有听众?【英文标题】:Does Subject.complete() unsubscribe all listeners?Subject.complete() 是否取消订阅所有听众? 【发布时间】:2017-03-20 01:50:01 【问题描述】:

我用这个方法构建了一个简单的确认对话服务(Angular 2):

confirm(body?: string, title?: string): Subject<void> 
    this.confirmation = new Subject<void>();
    // ... show dialog here... "are you sure?"
    return this.confirmation;


_onYesClicked() 
  // ... closing the dialog
  this.confirmation.next();
  this.confirmation.complete();
 

_onNoClicked() 
  // ... closing the dialog
  this.confirmation.complete();

用法:

confirmationService.confirm().subscribe(() => alert("CONFIRMED"));

如果有人使用该服务,他会返回一个 Subject(它是一个 Observable)并且可以“订阅()”它。单击“是”时会调用订阅,因此会给出确认...

这是正确的方法吗?更重要的是……会打电话给

this.confirmation.complete();

取消订阅已订阅的侦听器,从而防止任何延迟引用(内存泄漏)?

【问题讨论】:

我编辑了标题,因为complete() 方法不是 Obervable 接口的一部分。 【参考方案1】:

如果您想确保它会删除所有观察者,您可以在 https://github.com/ReactiveX/rxjs/blob/master/src/internal/Subject.ts#L91 中自行检查。它在所有观察者上调用complete()(观察者通常只是实现Observer interface 的哑对象),然后设置this.observers.length = 0;。所以答案是肯定的。

您的方法是有效的,它与 Angular2 对 EventEmitter 的常规做法基本相同。您可以改进的一件事是在公开Subjects 时开始使用asObservable()。这将隐藏您在下面使用Subject 并仅返回常规 Observable 的事实。这样您就不会让您的用户意外(或由于误解)尝试在您的 Subject 上调用 next()complete()error()

关于内存泄漏,这必须由 RxJS 处理,所以你不必担心,如果有问题,作者可能会在你之前注意到它。

也看看这个:Observable vs Subject and asObservable

【讨论】:

当用户单击 No 时,我也会调用 error() 而不是 complete()。或者我会使用 Promise 而不是 Observable。顺便说一句,ng-bootstrap modals 就是这样做的。 呵呵呵呵……真是天才,只看源头——这让我确信没有保留任何参考资料。对“asObservable()”也有很好的建议 - 谢谢! @JBNizet 我认为单击“否”并不一定意味着错误,但我猜这是 OP 的问题,而不是我的问题。 @JBNizet 无意冒犯,但这只是个坏建议。调用 error() 来指示有效的用户流不是好的设计。代码错误旨在表明技术上出现了问题,而不是表明用户在对话中说不。这样想:如果用户在询问“你想炸毁世界吗?”的对话框上单击“否”,我会说这不是错误。简而言之,错误是为可能导致程序中断的未处理代码流设计的,而不是指示在有效用例中接下来要采用哪个逻辑分支。 哇,多么棒的答案!因为这个,我今天学到了很多:)

以上是关于Subject.complete() 是不是取消订阅所有听众?的主要内容,如果未能解决你的问题,请参考以下文章

如何安装起订量框架

Magento 订单被收取两次费用

如何使用 MediatR 进行测试

我如何获得谷歌退款订单?

电商产品之订单拆分规则与流程

BILLING.SUBSCRIPTION.CANCELLED 不会在用户操作时触发?