Erstellen Sie ein einmaliges Abonnement


179

Ich muss ein Abonnement für ein Abonnement erstellen Observable, das sofort entsorgt wird, wenn es zum ersten Mal aufgerufen wird.

Gibt es so etwas wie:

observable.subscribeOnce(func);

In meinem Anwendungsfall erstelle ich ein Abonnement in einem Express-Routen-Handler und das Abonnement wird mehrmals pro Anfrage aufgerufen.

Antworten:


316

Nicht 100% sicher, was Sie brauchen, aber wenn Sie nur den ersten Wert beobachten möchten, verwenden Sie entweder first()oder take(1):

observable.first().subscribe(func);

Hinweis: .take(1)und .first()beide melden sich automatisch ab, wenn ihre Bedingung erfüllt ist

Update von RxJS 5.5+

Aus dem Kommentar von Coderer .

import { first } from 'rxjs/operators'

observable
  .pipe(first())
  .subscribe(func);

Hier ist der Grund


31
Wird das Abonnement danach automatisch bereinigt?
Berkeley Martinez

49
Ja tut es. Nehmen Sie und zuerst beide abbestellen, wenn ihre Bedingung erfüllt ist.
Brandon

20
Warum steht in der Dokumentation nicht, dass das Abonnement automatisch entsorgt wird?
Jzig

17
Es ist eine allgemeine RxJS-Regel, dass Abonnements entsorgt werden, wenn ein beobachtbarer Stream endet. Das bedeutet, dass jeder Operator, der einen Stream "verkürzt" (oder in einen anderen Stream-Typ umwandelt), den Quell-Stream abbestellt, wenn sein Vorgang abgeschlossen ist. Ich bin nicht sicher, wo oder ob dies in der Dokumentation angegeben ist.
Brandon

36
Wenn 2018 jemand dazu kommt, wollen Sie eigentlich observable.pipe(first()).subscribe(func), woher firstkommt rxjs/operators.
Coderer

32

RxJS hat einige der besten Dokumentationen, die mir je begegnet sind. Wenn Sie dem folgenden Link folgen, gelangen Sie zu äußerst hilfreichen Anwendungsfällen für die Tabellenzuordnung für Operatoren. Zum Beispiel unter dem Anwendungsfall „ich den ersten Wert zu übernehmen will“ sind drei Betreiber: first, firstOrDefault, und sample.

Hinweis: Wenn eine beobachtbare Sequenz ohne Benachrichtigungen abgeschlossen wird, firstbenachrichtigt der Bediener die Abonnenten mit einem Fehler, während der firstOrDefaultBediener den Abonnenten einen Standardwert bereitstellt.

Operator Use Case Lookup


2

Um die Antwort von @ Brandon zu ergänzen , ist die Verwendung von first()oder dergleichen auch wichtig, um eine BehaviorSubjectbasierend auf ihrer zu aktualisieren Observable. Zum Beispiel (ungetestet):

var subject = new BehaviorSubject({1:'apple',2:'banana'});
var observable = subject.asObservable();

observable
  .pipe(
    first(), // <-- Ensures no stack overflow
    flatMap(function(obj) {
      obj[3] = 'pear';
      return of(obj);
    })
  )
  .subscribe(function(obj) {
    subject.next(obj);
  });

2

Wenn Sie ein Observable nur einmal aufrufen möchten, bedeutet dies, dass Sie nicht auf einen Stream von ihm warten müssen. Die Verwendung von toPromise()anstelle von subscribe()würde in Ihrem Fall ausreichen, da toPromise()keine Abmeldung erforderlich ist.


Sehr interessant, das bedeutet auch, dass wir genau awaitdas können promise, was es zu einem Liner macht
Louie Almeda

@LouieAlmeda Könnten Sie uns ein Einzeiler-Beispiel geben?
Ado Ren

Hallo @AdoRen, ich habe die Technik in einer Antwort hier für Sie erläutert, ich hoffe, das hilft.
Louie Almeda

2

Saubere und bequeme Version

Hier ist die sehr praktische Version von M Fuat NUROĞLUs erstaunlicher Antwort auf die Umwandlung des Beobachtbaren in ein Versprechen.

const value = await observable.toPromise();

console.log(value)

Das Schöne daran ist, dass wir diesen Wert wie eine normale Variable verwenden können, ohne einen weiteren verschachtelten Block einzuführen!

Dies ist besonders praktisch, wenn Sie mehrere Werte von mehreren Observablen abrufen müssen. Ordentlich und sauber.

const content = await contentObservable.toPromise();
const isAuthenticated = await isAuthenticatedObservable.toPromise();

if(isAuthenticated){
   service.foo(content)
}

Natürlich müssen Sie Ihre Containing-Funktion festlegen, asyncwenn Sie diese Route wählen möchten. Sie können auch nur .thendas Versprechen abgeben, wenn die enthaltende Funktion nicht asynchron sein soll

Ich bin mir nicht sicher, ob es Kompromisse mit diesem Ansatz gibt. Lassen Sie es mich in den Kommentaren wissen, damit wir uns dessen bewusst sind.

PS Wenn Ihnen diese Antwort gefallen hat, vergessen Sie nicht, auch die Antwort von M Fuat NUROĞLU zu bewerten :)


0

Ich hatte eine ähnliche Frage.

Unten wurde noch später von verschiedenen Zustandswechslern aufgerufen. Da wollte ich nicht.

function foo() {
    // this was called many times which was not needed
    observable.subscribe(func);
    changeObservableState("new value");
}

Ich habe mich entschlossen, es unsubscribe()nach dem Abonnieren wie folgt zu versuchen .

function foo() {
    // this was called ONE TIME
    observable.subscribe(func).unsubscribe();
    changeObservableState("new value");
}

subscribe(func).unsubscribe();ist wie subscribeOnce(func).

Ich hoffe das hat dir auch geholfen.

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.