取消订阅一系列订阅

Posted

技术标签:

【中文标题】取消订阅一系列订阅【英文标题】:Unsubscribing an array of subscriptions 【发布时间】:2017-12-18 15:06:32 【问题描述】:

在一个 Angular 应用程序中,我通过将订阅全部推送到一个数组中来管理我的订阅,然后循环遍历它并在 ngOnDestroy 期间取消订阅。

private subscriptions: Subscription[] = []
this.subscriptions.push(someObservable.subscribe(foo => bar))

我的问题是我还没有找到足够干净的方法来处理退订。理想的方法是简单的

ngOnDestroy () 
    this.subscriptions.forEach(subscription => subscription.unsubscribe())

但这不起作用。值得注意的是,我在注销后仍然收到 Firebase 权限错误(“工作”方法不会发生这种情况)。有趣的是,如果我把它放到一个单独的类中,完全相同的方法确实可以工作:

export class Utils 
    public static unsubscribeAll (subObject: subscriptions: Subscription[]) 
        subObject.subscriptions.forEach(subscription => subscription.unsubscribe())
    


// ---------- back to the component

ngOnDestroy () 
    Utils.unsubscribeAll(subscriptions: this.subscriptions) // no Firebase errors

但我不太喜欢这个解决方案,主要是因为它只有在我将数组包装在一个对象中以便它作为引用传递时才有效。我发现的另一种工作方法是将其编写为 for 循环:

ngOnDestroy () 
    /* tslint:disable */
    for (let i = 0; i < this.subscriptions.length; i++) 
        this.subscriptions[i].unsubscribe()
    
    /* tslint:enable */

但除了不必要的长度之外,它也让 TSLint 抱怨,因为它认为我应该使用 for-of 循​​环代替(这不起作用)所以我每次都必须投入额外的 cmets。

目前我使用 Utils 选项作为“最佳”解决方案,但我仍然对此不满意。有没有我想念的更清洁的方法来做到这一点?

【问题讨论】:

奇怪,subscriptions.forEach(subscription =&gt; subscription.unsubscribe()) 等同于for (let i = 0; i &lt; this.subscriptions.length; i++) @Maximus 起初我认为这是复制而不是引用元素的一些底层区别,但我不明白为什么将它拉到一个单独的类中会起作用那个案子,所以我真的不知道这里发生了什么。 您能多谈谈您的订阅吗?在代码中展示它们以及它们的作用。还有read this article @Maximus 主要用于订阅 Firebase 数据。如果我不手动取消订阅,它会在我注销时引发权限错误。如果您想将其发布为答案,该链接会有所帮助(我没有意识到您可以将多个订阅一起添加,这几乎是我试图对数组进行的操作),尽管我仍然很好奇为什么它不是照原样工作。 我对 Angular 不是很熟悉,但注意到您的“工作”示例将订阅称为 this.subscriptions 而“不工作”就像 subscriptions 一样,这可能是相关的吗?不应该使用this 来访问对象成员吗?除此之外,Rx.Subscription 允许添加新订阅,然后一次性取消所有订阅,这意味着不需要该数组:const subscription = new Rx.Subscription(); subscription.add(source1.subscribe()); subscription.add(source2.subscribe()); subscription.unsubscribe(); 【参考方案1】:

由于没有人愿意发布他们的答案作为答案,我想我会这样做。

如果您只是使用数组对它们进行分组以进行大规模退订,则可以通过将它们合并到现有订阅中来完成相同的操作。对于我的设置,只需将空数组更改为空订阅并将push 更改为add

private subscriptions = new Subscription()
this.subscriptions.add(someObservable.subscribe(foo => bar))

然后,当您想全部取消订阅时,只需取消订阅容器订阅,它就会处理所有事情。

ngOnDestroy () 
    this.subscriptions.unsubscribe()

注意:您也可以在每个单独的订阅上使用takeUntil,但我觉得这种方法更简单,对我正在做的事情更有意义。

【讨论】:

但是,您将如何取消订阅一项特定的订阅?使用“添加”后,我的意思是。 @Rafael 在这种情况下,您需要维护一个单独的引用,例如this.foo = someObservable.subscribe(); this.subscriptions.add(this.foo),然后您可以单独或与所有其他人一起取消订阅。 不要使用 takeUntil,它会尝试关闭 observable,而不仅仅是订阅。由于来自 Subjects 的订阅在退订后仍然触发,它给我的应用程序带来了痛苦和破坏。【参考方案2】:
subs: Subscription[] = [];

ngOnInit(): void 
    this.subs.push(someObservable.subscribe(foo => bar));


ngOnDestroy(): void 
    this.subs.map(s => s.unsubscribe);

【讨论】:

小心,this.subs.map(s => s.unsubscribe) 不是取消订阅。

以上是关于取消订阅一系列订阅的主要内容,如果未能解决你的问题,请参考以下文章

XMPP 取消订阅/订阅状态泄露隐私

EventBus事件通信框架 ( 订阅方法注册 | 注册 事件类型 - 订阅类 + 订阅方法 到指定集合 | 取消注册 数据准备 )

条纹支付 - 如何暂停订阅(不取消)

在订阅之前取消订阅以前的请求

EventBus事件通信框架 ( 取消注册 | 获取事件参数类型 | 根据事件类型获取订阅者 | 移除相关订阅者 )

取消订阅 Apache pulsar 共享订阅类型