简体   繁体   中英

rxjs Observable: handle unsubscribe of all subscribe

I have a method that return a Observable

subFoo(id): Observable<number> {
    return new Observable<number>(observer => {
        setTimeout(() => {
            observer.next(id);
        }, 1000);
    });
}

now i subscribe it three time, and after 5 second unsubscribe all:

const sub1 = subFoo(1).subscribe(result => console.log(result));
const sub2 = subFoo(2).subscribe(result => console.log(result));
const sub3 = subFoo(3).subscribe(result => console.log(result));

setTimeout(() => {
  sub1.unsubscribe();
  sub2.unsubscribe();
  sub3.unsubscribe();
}, 5000);

i can handle the complete unsubscrite of all listners?

eg. (in pseudo code):

subFoo(id): Observable<number> {
    return new Observable<number>(observer => {

        // something like this
        observer.onAllListenerAreUnsubscribed(() => {
           console.log('All Listener Are Unsubscribed!');
        });

        setTimeout(() => {
            observer.next(id);
        }, 1000);
    });
}

Live demo: https://stackblitz.com/edit/angular-ayl12r

An Observable can know about subscriptions to its chains. If you want to be able to tell how many times someone subscribed you can count it yourself:

let subscriptions = 0;

subFoo(id): Observable<number> {
  return new Observable<number>(observer => {
    subscriptions++;
    ...
    return (() => {
      if (--subscriptions === 0) {
        // do whatever...
      }
      ...
    })
  })
})

You can also collect all subscriptions on the "observer side" into a single Subscription and then add a custom handler when you unsubscribe:

const subs = new Subscription();
subs.add(subFoo(1).subscribe(...));
subs.add(subFoo(2).subscribe(...));
subs.add(subFoo(3).subscribe(...));
subs.add(() => {
  // do whatever...
});

subs.unsubscribe(); // Will unsubscribe all subscriptions and then call your custom method.

you can unsubscribe all listeners in one single line so no need to handle that event

subscriptions.add(sub1).add(sub2).add(sub3);

// Then unsubscribe all of them with a single 
subscriptions.unsubscribe();

By completing all your observables at once, you are sure you will not get any data leakage. You can create a subject that will emit once the observables should stop emitting and use the takeUntil() operator on your observables, like so:

const completeSubscription: Subject<void> = new Subject();

const sub1 = subFoo(1)
  .pipe(takeUntil(completeSubscription))
  .subscribe(result => console.log(result));
const sub2 = subFoo(2)
  .pipe(takeUntil(completeSubscription))
  .subscribe(result => console.log(result));
const sub3 = subFoo(3)
  .pipe(takeUntil(completeSubscription))
  .subscribe(result => console.log(result));

setTimeout(() => {
  completeSubscription.next();
  completeSubscription.complete();
}, 5000);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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