Перетворити обіцянку на спостережливе


214

Я намагаюся обернути голову навколо спостережуваних. Мені подобається, як спостерігачі вирішують питання розвитку та читання. Як я читаю, вигоди величезні.

Спостереження на HTTP та колекціях, здається, прямо вперед. Як я можу перетворити щось подібне на шаблон, що спостерігається.

Це з мого сервісного компонента, щоб забезпечити автентифікацію. Я вважаю за краще, щоб це працювало як інші HTTP-сервіси в Angular2 - із підтримкою обробників даних, помилок та завершення.

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

Будь-яка допомога тут буде дуже вдячна. Єдиним альтернативним рішенням у мене було створення EventEmitters. Але я думаю, це жахливий спосіб робити речі в розділі послуг

Відповіді:


318

Якщо ви використовуєте RxJS 6.0.0:

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

9
Використовуючи 6.3.3, fromметод повернення спостерігається, але він надсилає обіцянку як значення для підписок. :(
Laxmikant Dange

1
Ця відповідь є коректною для RXJS 6+. Я намагався імпортувати operatorsчерез "інтуїцію" - я помилявся.
VSO

119

спробуйте це:

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

ви можете знайти повну посилання на оператора "Проміс" тут .


47
import 'rxjs/add/observable/fromPromise';
Саймон Бріггс

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

41

1 Пряме виконання / перетворення

Використовуйте fromдля прямого перетворення створеної раніше обіцянки в спостережувану.

import { from } from 'rxjs';

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

observable$буде гарячим спостереженням яке ефективно відтворює передплачені значення обіцянок.

Орган обіцянок виконується або вже був вирішений, коли створене спостережуване. Якщо внутрішня обіцянка була вирішена, новий абонент спостережуваного отримає свою вартість негайно.

2 Відкладене виконання на кожну підписку

Використовуйте deferз фабричною функцією для обіцянки як вхід, щоб відкласти створення та перетворення обіцянки на спостережуване.

import { defer } from 'rxjs';

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

observable$буде спостереження за холодом .

Різниця fromполягає в тому, що він deferчекає абонента і лише потім створює нову обіцянку, викликаючи дану функцію заводу обіцянки. Це корисно, коли ви хочете створити спостережуване, але не хочете, щоб внутрішня обіцянка була виконана відразу. Внутрішня обіцянка буде виконана лише тоді, коли хтось підписується на спостережуване. Кожен абонент також отримає свою нову спостережувану систему.

3 Багато операторів приймають обіцянки безпосередньо

Більшість RxJS операторів , які поєднують в собі (наприклад merge, concat, forkJoin, combineLatest...) або перетворити Спостережувані (наприклад switchMap, mergeMap, concatMap, catchError...) приймає обіцянки безпосередньо. Якщо ви все одно використовуєте один з них, вам не доведеться спочатку fromвиконувати обіцянку (але для створення холодного спостереження ви все ще можете використовувати defer).

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

Перевірте документацію або реалізацію , щоб побачити , якщо оператор ви використовуєте приймає ObservableInputабо 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>;

Різниця між fromі deferв прикладі: 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
Я думаю, що різниця - це капітал, дякую, що ви вказали на це.
Starscream

1

Ви також можете використовувати Subject і запускати наступну () функцію від обіцянки. Дивіться зразок нижче:

Додати код, як показано нижче (я використав послугу)

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

  }
}

Створіть користувача з компонента, як показано нижче

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


Предмети - це машини низького рівня. Не використовуйте теми, за винятком випадків, коли ви продовжуєте rxjs.
polkovnikov.ph

Я просто даю рішення.
Шиванг Гупта

Ви могли б принаймні показати new Observable(observer => { ... observer.next() ... })спосіб її реалізації. Незважаючи на те, що це було б повторним виконанням існуючої відомої функції, це безпосередньо відповість на питання і не було б шкідливим для читачів.
polkovnikov.ph


0

Ви можете додати обгортку навколо функціоналу обіцянки, щоб повернути спостережуваному спостерігачеві.

  • Створення ледачого спостереження за допомогою оператора defer (), який дозволяє створювати спостережуване лише тоді, коли спостерігач підписується.
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);
   }
)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.