Converti Promessa in Osservabile


215

Sto cercando di avvolgere la mia testa attorno a osservabili. Adoro il modo in cui gli osservabili risolvono i problemi di sviluppo e leggibilità. Mentre leggo, i benefici sono immensi.

Osservabili su HTTP e collezioni sembrano essere diretti. Come posso convertire qualcosa del genere in un modello osservabile.

Questo è dal mio componente del servizio, per fornire l'autenticazione. Preferirei che funzioni come altri servizi HTTP in Angular2, con supporto per gestori di dati, errori e completamento.

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;
    // ...
  });

Qualsiasi aiuto qui sarebbe molto apprezzato. L'unica soluzione alternativa che ho avuto è stata quella di creare EventEmitters. Ma immagino che sia un modo terribile di fare le cose nella sezione servizi

Risposte:


321

Se si utilizza RxJS 6.0.0:

import { from } from 'rxjs';
const observable = from(promise);

9
Usando 6.3.3, il frommetodo restituisce osservabile ma sta inviando promessa come valore agli abbonamenti. :(
Laxmikant Dange,

1
Questa risposta è corretta per RXJS 6+. Ho provato a importare operatorstramite "intuizione" - mi sbagliavo.
VSO,

119

prova questo:

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 */);

puoi trovare un riferimento completo all'operatore fromPromise qui .


47
import 'rxjs/add/observable/fromPromise';
Simon Briggs,

16
import { Observable } from "rxjs/Observable"; :)
Luckylooke,

41

1 Esecuzione / conversione diretta

Utilizzare fromper convertire direttamente una promessa precedentemente creata in osservabile.

import { from } from 'rxjs';

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

observable$sarà un osservabile a caldo che ripropone efficacemente il valore delle promesse agli abbonati.

Il corpo delle promesse viene eseguito o è già stato risolto quando viene creato l'osservabile. Se la promessa interiore è stata risolta, un nuovo abbonato all'osservabile otterrà immediatamente il suo valore.

2 Esecuzione differita su ogni iscrizione

Utilizzare defercon una funzione promessa di fabbrica come input per differire la creazione e la conversione di una promessa in osservabile.

import { defer } from 'rxjs';

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

observable$sarà un freddo osservabile .

La differenza fromè che deferaspetta un abbonato e solo allora crea una nuova promessa chiamando la funzione di fabbrica promessa data. Questo è utile quando vuoi creare un osservabile ma non vuoi che la promessa interiore venga eseguita immediatamente. La promessa interiore sarà eseguita solo quando qualcuno si iscriverà all'osservabile. Ogni abbonato riceverà anche il proprio nuovo osservabile.

3 Molti operatori accettano direttamente le promesse

La maggior parte degli operatori che combinano RxJS (ad esempio merge, concat, forkJoin, combineLatest...) o trasformare osservabili (ad esempio switchMap, mergeMap, concatMap, catchError...) accettano direttamente promesse. Se stai usando uno di essi comunque non devi usare fromper concludere una promessa (ma per creare un osservabile a freddo potresti ancora usare defer).

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

Controlla la documentazione o l' implementazione per vedere se l'operatore che stai utilizzando accetta ObservableInputo 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>;

La differenza tra frome deferin un esempio: 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);

4
Penso che la differenza sia capitale, grazie per averlo sottolineato.
Starscream,

1

Puoi anche usare un Soggetto e attivare la sua funzione next () dalla promessa. Vedi esempio di seguito:

Aggiungi codice come sotto (ho usato il servizio)

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);
          // ...
        });
    }

  }
}

Crea utente dal componente come di seguito

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


I soggetti sono macchinari di basso livello. Non utilizzare i soggetti, ad eccezione dei casi in cui si estende rxjs.
polkovnikov.ph,

Sto solo dando una soluzione.
Shivang Gupta,

Avresti potuto almeno mostrare il new Observable(observer => { ... observer.next() ... })modo di implementarlo. Anche se sarebbe una reimplementazione della funzione ben nota esistente, risponderebbe direttamente alla domanda e non sarebbe dannoso per i lettori.
polkovnikov.ph,


0

È possibile aggiungere un wrapper attorno alla funzionalità promessa per restituire un osservabile all'osservatore.

  • Creazione di un osservabile pigro utilizzando l' operatore defer () che consente di creare l'Osservabile solo quando l'osservatore si iscrive.
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);
   }
)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.