Versprechen in Observable umwandeln

213

Ich versuche, meinen Kopf um Observable zu wickeln. Ich mag die Art und Weise, wie Observables Entwicklungs- und Lesbarkeitsprobleme lösen. Während ich lese, sind die Vorteile immens.

Observables auf HTTP und Sammlungen scheinen einfach zu sein. Wie kann ich so etwas in ein beobachtbares Muster umwandeln?

Dies ist von meiner Servicekomponente, um die Authentifizierung bereitzustellen. Ich würde es vorziehen, wenn dies wie andere HTTP-Dienste in Angular2 funktioniert - mit Unterstützung für Daten-, Fehler- und Abschlusshandler.

firebase.auth().createUserWithEmailAndPassword(email, password)
  .then(function(firebaseUser) {
    // do something to update your UI component
    // pass user object to UI component
  })
  .catch(function(error) {
    // Handle Errors here.
    var errorCode = error.code;
    var errorMessage = error.message;
    // ...
  });

Jede Hilfe hier wäre sehr dankbar. Die einzige alternative Lösung, die ich hatte, war, EventEmitters zu erstellen . Aber ich denke, das ist eine schreckliche Art, Dinge im Dienstleistungsbereich zu tun

Krishnan Sriram
quelle

Antworten:

315

Wenn Sie RxJS 6.0.0 verwenden:

import { from } from 'rxjs';
const observable = from(promise);
Guillaume
quelle
9
Unter Verwendung von 6.3.3 gibt die fromMethode Observable zurück, sendet jedoch Versprechen als Wert an Abonnements. :(
Laxmikant Dange
1
Diese Antwort ist korrekt für RXJS 6+. Ich habe versucht, operatorsüber "Intuition" zu importieren - ich habe mich geirrt.
VSO
118

Versuche dies:

import 'rxjs/add/observable/fromPromise';
import { Observable } from "rxjs/Observable";

const subscription = Observable.fromPromise(
    firebase.auth().createUserWithEmailAndPassword(email, password)
);
subscription.subscribe(firebaseUser => /* Do anything with data received */,
                       error => /* Handle error here */);

Den vollständigen Verweis auf den fromPromise-Operator finden Sie hier .

Pate
quelle
47
import 'rxjs/add/observable/fromPromise';
Simon Briggs
16
import { Observable } from "rxjs/Observable"; :)
Luckylooke
40

1 Direkte Ausführung / Konvertierung

Verwenden Sie fromdiese Option, um ein zuvor erstelltes Versprechen direkt in ein Observable umzuwandeln.

import { from } from 'rxjs';

// getPromise() will only be called once
const observable$ = from(getPromise());

observable$wird ein heißes Observable sein , das den Versprechungswert für Abonnenten effektiv wiedergibt.

Der Versprechenskörper wird ausgeführt oder wurde bereits aufgelöst, als das Observable erstellt wurde. Wenn das innere Versprechen gelöst wurde, erhält ein neuer Abonnent des Observablen sofort seinen Wert.

2 Aufgeschobene Ausführung bei jedem Abonnement

Verwenden Sie diese Funktion defermit einer Versprechen-Factory-Funktion als Eingabe, um die Erstellung und Umwandlung eines Versprechens in ein Beobachtbares zu verschieben.

import { defer } from 'rxjs';

// getPromise() will be called every time someone subscribes to the observable$
const observable$ = defer(() => getPromise());

observable$wird eine Erkältung zu beobachten sein .

Der Unterschied frombesteht darin, dass deferauf einen Abonnenten gewartet wird und erst dann ein neues Versprechen erstellt wird, indem die angegebene Versprechen-Factory-Funktion aufgerufen wird. Dies ist nützlich, wenn Sie ein Observable erstellen möchten, aber nicht möchten, dass das innere Versprechen sofort ausgeführt wird. Das innere Versprechen wird nur ausgeführt, wenn jemand das Beobachtbare abonniert. Jeder Abonnent erhält außerdem seine eigene neue Beobachtungsgröße.

3 Viele Betreiber akzeptieren Versprechen direkt

Die meisten RxJS Operatoren , die kombinieren (zB merge, concat, forkJoin, combineLatest...) oder verwandeln Observablen (zB switchMap, mergeMap, concatMap, catchError...) direkt Versprechen akzeptieren. Wenn Sie eines davon trotzdem verwenden, müssen Sie es nicht verwenden from, um zuerst ein Versprechen zu verpacken (aber um ein kaltes Observable zu erstellen, müssen Sie es möglicherweise noch verwenden defer).

// Execute two promises simultaneously
forkJoin(getPromise(1), getPromise(2)).pipe(
  switchMap(([v1, v2]) => v1.getPromise(v2)) // map to nested Promise
)

Überprüfen Sie die Dokumentation oder Implementierung, um festzustellen, ob der von Ihnen verwendete Operator ObservableInputoder akzeptiert SubscribableOrPromise.

type ObservableInput<T> = SubscribableOrPromise<T> | ArrayLike<T> | Iterable<T>;
// Note the PromiseLike ----------------------------------------------------v
type SubscribableOrPromise<T> = Subscribable<T> | Subscribable<never> | PromiseLike<T> | InteropObservable<T>;

Der Unterschied zwischen fromund deferin einem Beispiel: https://stackblitz.com/edit/rxjs-6rb7vf

const getPromise = val => new Promise(resolve => {
  console.log('Promise created for', val);
  setTimeout(() => resolve(`Promise Resolved: ${val}`), 5000);
});

// the execution of getPromise('FROM') starts here, when you create the promise inside from
const fromPromise$ = from(getPromise('FROM'));
const deferPromise$ = defer(() => getPromise('DEFER'));

fromPromise$.subscribe(console.log);
// the execution of getPromise('DEFER') starts here, when you subscribe to deferPromise$
deferPromise$.subscribe(console.log);
Fridoo
quelle
4
Ich denke, dass Unterschied Kapital ist, danke, dass Sie darauf hingewiesen haben.
Starscream
1

Sie können auch einen Betreff verwenden und dessen next () -Funktion aus Versprechen auslösen . Siehe Beispiel unten:

Code wie unten hinzufügen (ich habe Service verwendet)

class UserService {
  private createUserSubject: Subject < any > ;

  createUserWithEmailAndPassword() {
    if (this.createUserSubject) {
      return this.createUserSubject;
    } else {
      this.createUserSubject = new Subject < any > ();
      firebase.auth().createUserWithEmailAndPassword(email,
          password)
        .then(function(firebaseUser) {
          // do something to update your UI component
          // pass user object to UI component
          this.createUserSubject.next(firebaseUser);
        })
        .catch(function(error) {
          // Handle Errors here.
          var errorCode = error.code;
          var errorMessage = error.message;
          this.createUserSubject.error(error);
          // ...
        });
    }

  }
}

Erstellen Sie einen Benutzer aus einer Komponente wie unten

class UserComponent {
  constructor(private userService: UserService) {
    this.userService.createUserWithEmailAndPassword().subscribe(user => console.log(user), error => console.log(error);
    }
  }

Shivang Gupta
quelle
Themen sind Maschinen auf niedriger Ebene. Verwenden Sie keine Themen, außer in den Fällen, in denen Sie erweitern rxjs.
polkovnikov.ph
Ich gebe nur eine Lösung.
Shivang Gupta
Sie hätten zumindest zeigen können, new Observable(observer => { ... observer.next() ... })wie Sie es implementieren können. Obwohl es sich um eine Neuimplementierung bestehender bekannter Funktionen handeln würde, würde es die Frage direkt beantworten und wäre für die Leser nicht schädlich.
polkovnikov.ph
1

Sie können auch defer verwenden . Der Hauptunterschied besteht darin, dass das Versprechen nicht eifrig gelöst oder abgelehnt wird.

Mateja Petrovic
quelle
0

Sie können einen Wrapper um die Versprechen-Funktionalität hinzufügen, um ein Observable an den Beobachter zurückzugeben.

  • Erstellen eines Lazy Observable mit dem Operator defer (), mit dem Sie das Observable nur erstellen können, wenn der Observer es abonniert.
import { of, Observable, defer } from 'rxjs'; 
import { map } from 'rxjs/operators';


function getTodos$(): Observable<any> {
  return defer(()=>{
    return fetch('https://jsonplaceholder.typicode.com/todos/1')
      .then(response => response.json())
      .then(json => {
        return json;
      })
  });
}

getTodos$().
 subscribe(
   (next)=>{
     console.log('Data is:', next);
   }
)

Khizer
quelle