简体   繁体   English

RXJS - 同时使用 take(1) 和 takeUntil()

[英]RXJS - Using both take(1) and takeUntil()

After searching online, I see that people generally use one or the other and not both.在网上搜索后,我看到人们通常使用一种或另一种,而不是两者都使用。 Is it possible to use both?可以同时使用吗? Is it good or bad practice?这是好还是坏的做法?

Edit编辑

I am not asking what take(1) or takeUntil is used for.我不是在问 take(1) 或 takeUntil 是干什么用的。 Rather I am asking if it is possible to have both effects of take(1) and takeUntil.相反,我在问是否有可能同时具有 take(1) 和 takeUntil 的效果。 I understand that take(1) will take only the first value and end the subscription.我知道 take(1) 将只取第一个值并结束订阅。 However, it will not end the subscription if I never receive the event.但是,如果我从未收到该事件,它不会结束订阅。 I also understand that this use of takeUntil will always clean up the subscription when the component is no longer active as long as I trigger the unsubscribeSubject in the destroy.我也明白,只要我在销毁中触发 unsubscribeSubject,当组件不再活动时,takeUntil 的这种使用将始终清除订阅。 However, it will not free up that subscription after I receive the first value and will exist for the entire time the component is active.但是,它不会在我收到第一个值后释放该订阅,并且会在组件处于活动状态的整个时间内存在。

What I want is a way to free the subscription after the first value as well as prevent memory leaks when the component is no longer active if not value is received.我想要的是一种在第一个值之后释放订阅的方法,并在未收到值时组件不再处于活动状态时防止内存泄漏。 Specifically in a scenario where you have many subscriptions.特别是在您有很多订阅的情况下。 This is because when you have many subscriptions, it is handy to have a single subject that can clean up all your subscriptions when the component is no longer needed.这是因为当您有很多订阅时,当不再需要该组件时,拥有一个可以清理所有订阅的主题会很方便。

ngAfterViewInit(){
    //if first value comes, we process it and unsubscribe
    this.myService.GetOneTimeObservable()
        .pipe(take(1))
        .pipe(takeUntil(this.unsubscribeSubject))
        .subscribe(this.fooOT.bind(this))

    //other subscriptions (assume many)
    this.myService.GetLongLifeObservable1()
        .pipe(takeUntil(this.unsubscribeSubject))
        .subscribe(this.foo1.bind(this))

    this.myService.GetLongLifeObservable2()
        .pipe(takeUntil(this.unsubscribeSubject))
        .subscribe(this.foo2.bind(this))

    this.myService.GetLongLifeObservable3()
        .pipe(takeUntil(this.unsubscribeSubject))
        .subscribe(this.foo3.bind(this))
}

ngOnDestroy(){
    //Ideally cleans all subscriptions, including the OneTime if no value is received
    this.unsubscribeSubject.next();
    this.unsubscribeSubject.complete();
}

take(1) is not guaranteed to cancel the observable because it may not have emitted before the component is destroyed. take(1) 不能保证取消 observable,因为它可能在组件被销毁之前没有发出。 The takeUntil guarantees that the observable is not a memory leak. takeUntil 保证 observable 不是内存泄漏。 If the observable is taking a long time to emit before the component is destroyed and you only have a take(1) and you move on to another component the subscription is still listening and will fire even though the component is no longer active.如果 observable 在组件销毁之前需要很长时间才能发出,并且您只有一个 take(1) 并且您移动到另一个组件,则订阅仍在侦听并且即使组件不再处于活动状态也会触发。

The only reason to use take(1) is if the subject might emit more than once and you only want the first value, takUntil is enough to make sure that there is not a memory leak.使用 take(1) 的唯一原因是,如果主体可能发出不止一次,而您只想要第一个值,takUntil 足以确保没有内存泄漏。

Shortly: yes, it's possible to use both.简短地说:是的,可以同时使用两者。 You can try by yourself using this example:您可以使用此示例自行尝试:

import { fromEvent, timer } from 'rxjs'; 
import { map, takeUntil, take } from 'rxjs/operators';

const source = fromEvent(document, 'click');
const destruct = timer(5000);

source.pipe(
  takeUntil(destruct), //the order of take/takeUntil doesn't matter
  take(1),
).subscribe(
  () => console.log('click'),
  () => console.log('error'),
  () => console.log('complete')
); 

Observable is completed on first click OR destruct event (here simulated by timer). Observable 在第一次单击或销毁事件时完成(此处由计时器模拟)。 In my opinion it is not a bad practice, but I'm not specialist.在我看来,这不是一个坏习惯,但我不是专家。

If your thought process is: "I know I could get multiple emitted values but just want the first one."如果您的思考过程是:“我知道我可以得到多个发出的值,但只想要第一个。” and "I may get no values and want the subscription unsubscribed on component destroy."和“我可能没有任何价值,并希望在组件销毁时取消订阅。” then create a class variable to store the subscription and unsubscribe from that on destroy.然后创建一个类变量来存储订阅并在销毁时取消订阅。

private oneTimeSubscription: Subscription;

ngAfterViewInit(){
  this.oneTimeSubscription = this.myService.GetOneTimeObservable()
    .pipe(take(1))
    .subscribe(this.fooOT.bind(this))
}

ngOnDestroy(){
  this.oneTimeSubscription.unsubscribe();
}

or you could unsubscribe in-line:或者您可以在线取消订阅:

ngAfterViewInit(){
  const oneTimeSubscription: Subscription = this.myService.GetOneTimeObservable()
    .pipe(take(1))
    .subscribe(this.fooOT.bind(this, oneTimeSubscription))
}

fooOT(subscription: Subscription): void {
  subscription.unsubscribe();
  // rest of your code here...
}

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

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