So kündigen Sie ein Abonnement in Angular2


80

Wie kündigt man ein Abonnement in Angular2? RxJS scheint eine Entsorgungsmethode zu haben, aber ich kann nicht herausfinden, wie ich darauf zugreifen soll. Ich habe also Code, der Zugriff auf einen EventEmitter hat und ihn wie folgt abonniert:

var mySubscription = someEventEmitter.subscribe(
    (val) => {
        console.log('Received:', val);
    },
    (err) => {
        console.log('Received error:', err);
    },
    () => {
        console.log('Completed');
    }
);

Wie kann ich mySubscriptiondas Abonnement kündigen?


2
Zu Ihrer Information: Wenn Sie reaktive Dinge tun möchten, verwenden Sie einen Betreff anstelle von Angulars EventEmitter. Es gibt keine Garantie dafür, dass es sich um eine Oberklasse von Betreff handelt. Verwenden Sie EventEmitter nur für @ Output-Ereignisse.
Robwormald

Antworten:


118

Möchten Sie sich abmelden?

mySubscription.unsubscribe();

4
Guter Herr. Ich habe geschworen, dass ich das schon versucht habe. Ich schaute auf die RxJS-Quelle und das schien so zu sein. Ich muss einen anderen Fehler gehabt haben, der mir Probleme verursacht hat. Vielen Dank.
Michael Oryl

1
Das funktioniert gut, aber ich bin gespannt, welche Art von mySubscriptionTypeScript verwendet wird. Ich möchte vermeiden, mySubscription: anyin meiner Klasse zu schreiben .
Paradite

11
@paradite import { Subscription } from "rxjs";und zur Abmeldung if (!mySubscription.closed) { mySubscription.unsubscribe(); }.
Llyle

9
import { Subscription } from 'rxjs/Subscription';wird helfen, Ihre Paketgröße niedrig zu halten
Paul

50

Ich dachte, ich stecke auch meine zwei Cent ein. Ich benutze dieses Muster:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs/Subscription';

@Component({
    selector: 'my-component',
    templateUrl: 'my.component.html'
})
export class MyComponent implements OnInit, OnDestroy {

    private subscriptions: Array<Subscription> = [];

    public ngOnInit(): void {
        this.subscriptions.push(this.someService.change.subscribe(() => {
            [...]
        }));

        this.subscriptions.push(this.someOtherService.select.subscribe(() => {
            [...]
        }));
    }

    public ngOnDestroy(): void {
        this.subscriptions.forEach((subscription: Subscription) => {
            subscription.unsubscribe();
        });
    }
}

BEARBEITEN

Ich habe neulich die Dokumentation gelesen und ein empfohleneres Muster gefunden:

ReactiveX / RxJS / Abonnement

Vorteile:

Es verwaltet die neuen Abonnements intern und fügt einige ordentliche Überprüfungen hinzu. Würde diese Methode in der Funktion bevorzugen :).

Nachteile:

Es ist nicht 100% klar, wie der Codefluss aussieht und wie Abonnements betroffen sind. Es ist auch nicht klar (nur anhand des Codes), wie es mit geschlossenen Abonnements umgeht und ob alle Abonnements geschlossen werden, wenn das Abbestellen aufgerufen wird.

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs/Subscription';

@Component({
    selector: 'my-component',
    templateUrl: 'my.component.html'
})
export class MyComponent implements OnInit, OnDestroy {

    private subscription: Subscription = new Subscription();

    public ngOnInit(): void {
        this.subscription.add(this.someService.change.subscribe(() => {
            [...]
        }));

        this.subscription.add(this.someOtherService.select.subscribe(() => {
            [...]
        }));
    }

    public ngOnDestroy(): void {
        /*
         * magic kicks in here: All subscriptions which were added
         * with "subscription.add" are canceled too!
         */
        this.subscription.unsubscribe();
    }
}

2
Ich benutze dies auch, es skaliert gut, je mehr Abonnements Sie in einer Komponente haben.
Weltschmerz

1
Keine "Magie" - es ist beabsichtigt: "Abonnements können auch zusammengestellt werden, sodass ein Aufruf eines Abonnements () eines Abonnements mehrere Abonnements abbestellen kann. Sie können dies tun, indem Sie ein Abonnement zu einem anderen" hinzufügen ":" github. com / ReactiveX / rxjs / blob / master / doc / abonnement.md
Meetai.com

Es gibt noch einen anderen klaren Ansatz, an dem Sie interessiert sein könnten. Verwenden des takeWhileOperators. Ansatz hier beschrieben: brianflove.com/2016/12/11/anguar-2-unsubscribe-observables
vdshb

Schauen Sie sich eine alternative Lösung an , die takeUntil verwendet. Es gibt eine reiche und interessante Diskussion, die verschiedene Optionen in Betracht zieht.
Alex Klaus

8

BEARBEITEN: Dies gilt nicht für RxJS 5, das von angle2 verwendet wird.

Ich hätte gedacht, Sie suchen nach der Entsorgungsmethode für Einwegartikel .

Die Subscribe-Methode gibt ein Disposable ( Link ) zurück.

Ich kann es nicht expliziter in den Dokumenten finden, aber das funktioniert ( jsbin ):

var observable = Rx.Observable.interval(100);

var subscription = observable.subscribe(function(value) {
   console.log(value);
});

setTimeout(function() {
  subscription.dispose();           
}, 1000)

Seltsamerweise scheint das Abbestellen für Sie zu funktionieren, während es für mich nicht funktioniert ...


Sie verwenden wahrscheinlich verschiedene Versionen. Angular2 ist auf Rxjs5, nicht wahr?
user3743222

Ja, Angular 2 verwendet RxJS 5.
Michael Oryl

1
Das ist es. Kann hier gefunden werden . Die Änderung wurde vorgenommen, um der ES7 Observable Spec
Niklas Fasching

4

Viel zu viele verschiedene Erklärungen zum Abbestellen von Observables für ng2 haben mich ewig gekostet, um die richtige Antwort zu finden. Unten ist ein funktionierendes Beispiel (ich habe versucht, die Mausbewegung zu drosseln).

import {Injectable, OnDestroy} from "@angular/core";
import {Subscription} from "rxjs";

@Injectable()
export class MyClass implements OnDestroy {
  
  mouseSubscription: Subscription; //Set a variable for your subscription
  
  myFunct() {
    // I'm trying to throttle mousemove
    const eachSecond$ = Observable.timer(0, 1000);
    const mouseMove$ = Observable.fromEvent<MouseEvent>(document, 'mousemove');
    const mouseMoveEachSecond$ = mouseMove$.sample(eachSecond$);
    
    this.mouseSubscription = mouseMoveEachSecond$.subscribe(() => this.doSomethingElse());
  }

  doSomethingElse() {
    console.log("mouse moved");
  }
  
  stopNow() {
    this.mouseSubscription.unsubscribe();
  }
  
  ngOnDestroy() {
    this.mouseSubscription.unsubscribe();
  }
  
}


2
ngOnDestroy(){
   mySubscription.unsubscribe();
}

Ziehen Sie es vor, rxjs abzumelden, während Sie die Komponente zerstören, dh aus dem DOM entfernen, um unnötige Speicherlecks zu vermeiden


2

Ich persönlich bevorzuge es, einen Betreff zu verwenden, um alle Abonnements zu schließen, die eine Komponente im Schritt "Lebenszyklus zerstören" möglicherweise hat. Dies kann auf folgende Weise erreicht werden:

import { Component} from '@angular/core';
import { Subject } from "rxjs/Rx";

@Component({
  selector:    'some-class-app',
  templateUrl: './someClass.component.html',
  providers:   []
})

export class SomeClass {  

  private ngUnsubscribe: Subject<void> = new Subject<void>(); //This subject will tell every subscriptions to stop when the component is destroyed.

  //**********
  constructor() {}

  ngOnInit() {

    this.http.post( "SomeUrl.com", {}, null ).map( response => {

      console.log( "Yay." );

    }).takeUntil( this.ngUnsubscribe ).subscribe(); //This is where you tell the subscription to stop whenever the component will be destroyed.
  }

  ngOnDestroy() {

    //This is where we close any active subscription.
    this.ngUnsubscribe.next();
    this.ngUnsubscribe.complete();
  }
}

1

Verwenden

if(mySubscription){
  mySubscription.unsubscribe();
}

1
Eigentlich sollteif (!mySubscription.closed) { mySubscription.unsubscribe(); }
Llyle

1

Der empfohlene Ansatz besteht darin, RxJS-Operatoren wie den takeUntil- Operator zu verwenden. Unten sehen Sie das Code-Snippet, das zeigt, wie es verwendet wird: -

import { Component, OnInit, OnDestroy } from '@angular/core';
import { interval, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html'
})
export class AppComponent implements OnInit, OnDestroy {
    private ngUnsubscribe = new Subject();

    constructor() { }

    ngOnInit() {
        var observable1 = interval(1000);
        var observable2 = interval(2000);

        observable1.pipe(takeUntil(this.ngUnsubscribe)).subscribe(x => console.log('observable1: ' + x));
        observable2.pipe(takeUntil(this.ngUnsubscribe)).subscribe(x => console.log('observable2: ' + x));
    }

    ngOnDestroy() {
        this.ngUnsubscribe.next();
        this.ngUnsubscribe.complete();
    }
}

Eine ausführliche Erläuterung des Themas finden Sie hier


warum wir ngUnsubscribe.next () aufrufen müssen; in der ngOnDestroy () -Methode?
Biswa Bandhu Bhandary
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.