Konwertuj obietnicę na Obserowalną

214

Próbuję owinąć głowę wokół obserwowalnych. Uwielbiam sposób, w jaki obserwowalne rozwiązania problemów związanych z rozwojem i czytelnością. Jak czytam, korzyści są ogromne.

Obserwowalne na HTTP i kolekcjach wydają się być proste. Jak przekonwertować coś takiego na obserwowalny wzór.

Pochodzi z mojego komponentu usługi, aby zapewnić uwierzytelnianie. Wolę, aby działało to tak, jak inne usługi HTTP w Angular2 - z obsługą danych, procedur obsługi błędów i uzupełniania.

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

Każda pomoc tutaj będzie mile widziana. Jedynym alternatywnym rozwiązaniem, jakie miałem, było stworzenie EventEmitters. Ale to chyba okropny sposób na robienie rzeczy w dziale usług

Krishnan Sriram
źródło

Odpowiedzi:

318

Jeśli używasz RxJS 6.0.0:

import { from } from 'rxjs';
const observable = from(promise);
Guillaume
źródło
9
Przy użyciu 6.3.3 frommetoda zwraca obserwowalny, ale wysyła obietnicę jako wartość do subskrypcji. :(
Laxmikant Dange
1
Ta odpowiedź jest poprawna dla RXJS 6+. Próbowałem importować z operators„intuicji” - myliłem się.
VSO
119

Spróbuj tego:

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

Pełne odniesienie do operatora fromPromise można znaleźć tutaj .

Ojciec chrzestny
źródło
47
import 'rxjs/add/observable/fromPromise';
Simon Briggs
16
import { Observable } from "rxjs/Observable"; :)
Luckylooke,
41

1 Bezpośrednie wykonanie / konwersja

Służy fromdo bezpośredniego konwertowania wcześniej utworzonej obietnicy na obserwowalne.

import { from } from 'rxjs';

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

observable$będzie gorący do zaobserwowania który skutecznie odtworzy wartość obietnic dla subskrybentów.

Ciało obietnic jest wykonywane lub zostało już rozwiązane podczas tworzenia obserwowalnego. Jeśli wewnętrzna obietnica została rozwiązana, nowy subskrybent obserwowalnego natychmiast uzyska swoją wartość.

2 Odroczone wykonanie każdego subskrypcji

Użyj deferz funkcją fabryki obietnic jako danych wejściowych, aby odroczyć tworzenie i przekształcanie obietnicy w obserwowalne.

import { defer } from 'rxjs';

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

observable$będzie zimno obserwowalny .

Różnica frompolega na tym, żedefer czeka na subskrybenta, a dopiero potem tworzy nową obietnicę, wywołując daną funkcję fabryki obietnic. Jest to przydatne, gdy chcesz stworzyć obserwowalne, ale nie chcesz od razu wykonać wewnętrznej obietnicy. Wewnętrzna obietnica zostanie wykonana tylko wtedy, gdy ktoś zasubskrybuje to, co obserwowalne. Każdy subskrybent otrzyma także własny nowy obserwowalny.

3 Wielu operatorów bezpośrednio przyjmuje obietnice

Większość RxJS podmioty, które łączą (np merge, concat, forkJoin, combineLatest...) lub przekształcić obserwable (np switchMap, mergeMap, concatMap, catchError...) przyjąć obietnice bezpośrednio. Jeśli i tak używasz jednego z nich, nie musisz fromnajpierw zawijać obietnicy (ale aby stworzyć zimny obserwowalny , nadal będziesz musiał skorzystać defer).

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

Sprawdź dokumentację lub implementację, aby sprawdzić, czy używany operator akceptuje ObservableInputlub 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>;

Różnica między fromi deferw przykładzie: 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
źródło
4
Myślę, że ta różnica to kapitał, dzięki za zwrócenie na to uwagi.
Starscream,
1

Możesz także użyć podmiotu i uruchomić jego funkcję next () z obietnicy. Zobacz próbkę poniżej:

Dodaj kod jak poniżej (korzystałem z usługi)

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

  }
}

Utwórz użytkownika z komponentu jak poniżej

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

Shivang Gupta
źródło
Badani są maszynerią niskiego poziomu. Nie używaj tematów, z wyjątkiem przypadków przedłużania rxjs.
polkovnikov.ph
Po prostu daję rozwiązanie.
Shivang Gupta,
Mogłeś przynajmniej pokazać new Observable(observer => { ... observer.next() ... })sposób na jego wdrożenie. Mimo że byłby to reimplementacja istniejącej dobrze znanej funkcji, odpowiadałaby bezpośrednio na pytanie i nie byłaby szkodliwa dla czytelników.
polkovnikov.ph
1

Możesz także użyć opcji odroczenia . Główną różnicą jest to, że obietnica nie będzie chętnie rozstrzygana ani odrzucana.

Mateja Petrovic
źródło
0

Możesz dodać opakowującą funkcjonalność obietnicy, aby zwrócić Observera obserwatorowi.

  • Tworzenie leniwego obserwowalnego za pomocą operatora defer () , który pozwala tworzyć obserwowalny tylko wtedy, gdy obserwator subskrybuje.
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);
   }
)

chizer
źródło