取消订阅一系列的订阅数组

24
在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循环(但这行不通),所以我不得不每次加上额外的注释。

目前,我正在使用Utils选项作为“最佳”解决方案,但我仍然对此不满意。我有没有错过更简洁的方法呢?


2
奇怪的是,subscriptions.forEach(subscription => subscription.unsubscribe()) 相当于 for (let i = 0; i < this.subscriptions.length; i++) { - Max Koretskyi
@Maximus 起初我以为这是一些底层的区别,其中它复制而不是引用元素,但如果将其提取到单独的类中,我无法弄清楚为什么会起作用,所以我真的不知道在这里发生了什么。 - John Montgomery
你能多讲一些关于你的订阅的内容吗?用代码展示它们的作用。另外,阅读这篇文章:https://medium.com/@benlesh/rxjs-dont-unsubscribe-6753ed4fda87 - Max Koretskyi
1
我不太熟悉Angular,但是注意到你的“工作”示例将订阅称为this.subscriptions,而“不工作”的示例只是subscriptions,这可能有关系吗?难道不应该使用this来访问对象成员吗?除此之外,Rx.Subscription允许添加新的订阅,然后一次性取消所有订阅,这意味着不需要数组:const subscription = new Rx.Subscription(); subscription.add(source1.subscribe()); subscription.add(source2.subscribe()); subscription.unsubscribe(); - Sergey Karavaev
你可能想看一下这个问题。顶部的答案提供了一种在ngOnDestroy中取消订阅而不必跟踪大量订阅的方法。虽然并没有更容易,但是确实稍微简单了一点。 - Pace
显示剩余2条评论
2个回答

62

既然没有人愿意把他们的答案发布为答案,我猜我会这样做。

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

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

然后,当您想要取消订阅所有内容时,只需取消订阅容器订阅即可,它将处理一切。

ngOnDestroy () {
    this.subscriptions.unsubscribe()
}

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


你怎么取消一个特定的订阅呢?在使用“add”之后,我的意思是。 - Rafael
2
@Rafael 在这种情况下,您需要单独维护对它的引用,例如 this.foo = someObservable.subscribe(); this.subscriptions.add(this.foo),然后您可以单独取消订阅它或与其他所有订阅一起取消订阅。 - John Montgomery
不要使用takeUntil,它试图关闭可观察对象,而不仅仅是订阅。由于来自Subjects的订阅在取消订阅后仍然触发,因此它会在我的应用程序中创建痛苦和混乱。 - John White

-1
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) 是取消订阅,而不是取消。 - Leasye

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