简体   繁体   English

什么方法更适合杀死一个可观察的,为takeUntil运算符提供,为什么?

[英]What approach is better for killing an observable, provided for takeUntil operator, and why?

I have a question about one of the common pattern for the unsubscribing with the takeUntil operator for Angular and RxJs. 我有一个关于使用Angular和RxJs的takeUntil运算符取消订阅的常见模式之一的问题。 In this article , it 's under the third position. 这篇文章中 ,它处于第三位。 For example, we have such code in a component class: 例如,我们在组件类中有这样的代码:

  private destroy$: Subject<boolean> = new Subject();

  ngOnInit() {
     this.control.
     .pipe(takeUntil(this.destroy$)
     .subscribe(doSmthngFunc); 
  }

  ngOnDestroy() {
    this.destroy$.next(true);
    // Which next line of code is correct?
    // this.destroy$.complete()     // this one?
    // this.destroy$.unsubscribe()  // or this one?
  }

The first line this.destroy$.next(true) is totally clear. 第一行this.destroy $ .next(true)完全清楚。 But the second is not. 但第二个不是。 If we look into the realization of these methods, we find that they have somewhat similar behavior. 如果我们研究这些方法的实现,我们发现它们有一些类似的行为。 complete(): unsubscribe(): complete(): unsubscribe():

As I understand semantically complete() is preferable, because we call next() for the first and the last time during the component life and then we finished with this Subject, treated as Observable and can invoke complete(). 据我所知,语义上complete()是首选,因为我们在组件生命期间的第一次和最后一次调用next()然后我们完成了这个Subject,被视为Observable并且可以调用complete()。 These methods belong to the observer and unsubscribe belong to the observable, and we have no subscriptions to unsubscribe from. 这些方法属于观察者,取消订阅属于observable,我们没有订阅取消订阅。 But under the hood, these methods have a similar code: 但在幕后,这些方法有类似的代码:

    this.isStopped = true; // both

    this.observers.length = 0; // complete
    this.observers = null;     // unsubscribe

    this.closed = true;        // only unsubscribe

Theoretically complete() has delayed effect as it's may invoke complete() on every observer subscribed, but we have no observers on destroy$. 理论上,complete()具有延迟效果,因为它可以在每个订阅的观察者上调用complete(),但我们没有观察者对destroy $。 So the question - which way is more preferable, less error-prone, and why? 所以问题是 - 哪种方式更可取,更不容易出错,为什么?

I do not think you need to do much more than destroy$.next(); 我不认为你需要做的不仅仅是destroy$.next(); . destroy$ is a Subject you created in your class, and the only thing it is responsible for is aborting your subscription. destroy$是您在班级中创建的Subject ,它唯一负责的就是中止您的订阅。 No one, but your class is allowed to touch it (since it is private) 没有人,但你的班级可以接触它(因为它是私人的)

According to the article, it is better to do a destroy$.complete() to avoid memory leaks. 根据文章,最好做一个destroy$.complete()来避免内存泄漏。 I do not think using unsubscribe() on it makes any sense. 我认为使用unsubscribe()没有任何意义。 If someone subscribed to destroy$ , you should store that in a Subscription, and unsubscribe in the callers ngOnDestroy() -method. 如果某人订阅了destroy$ ,则应将其存储在订阅中,并取消订阅调用者ngOnDestroy() - ngOnDestroy() However, since you are using takeUntil , there is no need for an unsubscribe. 但是,由于您使用的是takeUntil ,因此无需取消订阅。

Destruction of a component is a singular event. 破坏组件是一个单一事件。

   this.destroy$.next();
   this.destroy$.complete();

Ensures that the subject emits only once and completes . 确保主题仅发出一次完成

For example; 例如;

    const destroy$ = new Subject();

    destroy$.subscribe(v => console.log("destroyed"));

    destroy$.next();
    destroy$.complete();
    destroy$.next();

    // the above prints "destroyed" only once.

It's not a technical requirement to complete, but if you don't then business logic that depends upon completion instead of emission will not always work, and might leak memory. 完成这不是技术要求,但如果不这样做,那么取决于完成而不是排放的业务逻辑将不会始终有效,并且可能会泄漏内存。

For example, the following would be a memory leak in RxJs. 例如,以下是RxJ中的内存泄漏。

   destroyed$.subscribe(() => {
       console.log('This might leak memory');
   });

The above could leak memory because the subscription never ends and the observable never completes. 以上内容可能会泄漏内存,因为订阅永远不会结束,而且observable永远不会完成。 You can fix the leak by adding a first() operator or making sure the subject is completed. 您可以通过添加first()运算符或确保主题已完成来修复泄漏。 RxJS does not know that the subject will only emit one value, and so you have to tell it. RxJS不知道主题只会发出一个值,所以你必须告诉它。 Otherwise subscribers remain bound to the stack frame and are not garbage collected. 否则订户仍然绑定到堆栈帧并且不会被垃圾回收。 So while the garbage collector might collect the component after it is used if anything references the stack frame of the subscriber, then that subscription lives on. 因此,虽然垃圾收集器可能在使用它之后收集组件,如果有任何东西引用了订阅者的堆栈帧,那么该订阅仍然存在。

So call complete on your destroy subjects so that other people don't make mistakes. 所以在你的摧毁主题上打电话完成 ,这样其他人就不会犯错误。

this.destroy$.unsubscribe() this.destroy $ .unsubscribe()

Calling unsubscribe on a subject might not have an effect on downstream operators that create inner subscriptions. 调用取消订阅某个主题可能不会对创建内部订阅的下游运营商产生影响。 For example, switchMap() and mergeMap() create inner subscriptions. 例如, switchMap()mergeMap()创建内部订阅。

So you can not manage subscriptions higher up effectively. 因此,您无法有效地管理更高的订阅。 It's better to unsubscribe from the subscription created when you call the subscribe() method, because this is last in the chain of operators. 最好取消订阅调用subscribe()方法时创建的subscribe() ,因为这是运算符链中的最后一个。

Both statements will have the desired effect. 这两个陈述都会产生预期的效果。 Afaik there's no technical reason not to use unsubscribe . Afaik没有技术理由不使用unsubscribe Semantically - as you mentioned - it makes a lot more sense to use complete . 在语义上 - 正如你所提到的 - 使用complete更有意义。

A Subject is both an observable (sending) and an observer (listening), and that duality is reflected here. 主体既是可观察的(发送的)又是观察者的(倾听的),并且这种二元性在这里得到反映。 next and complete both belong to the 'sending' side of things. nextcomplete都属于'发送'方面的东西。 complete signals 'this stream will not send any further values'. complete信号'此流不会发送任何其他值'。 unsubscribe is part of the 'listening' interface and has a correspondingly different meaning: 'don't notify me of any further emissions'. unsubscribe是“倾听”界面的一部分,具有相应的不同含义:“不要通知我任何进一步的排放”。

Edit: on re-reading I see you've already included this distinction in the question, so my answer probably doesn't add much for you :(. I do think the semantics is important enough in its own right for using complete over unsubscribe here, and can see no actual risk of using the one over the other in this pattern. Hope that's still somewhat helpful! 编辑:在重新阅读时我看到你已经在问题中包含了这个区别,所以我的答案可能并没有为你增添太多:(。我认为语义本身就足以使用完全取消订阅在这里,并且可以看到在这种模式中没有使用这个的实际风险。希望这仍然有点帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM