Преобразовать обещание в наблюдаемое

215

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

Наблюдаемые данные по 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. Но я думаю, что это ужасный способ сделать что-то в разделе услуг

Кришнан Шрирам
источник

Ответы:

322

Если вы используете RxJS 6.0.0:

import { from } from 'rxjs';
const observable = from(promise);
Гийом
источник
9
Используя 6.3.3, fromметод возвращает наблюдаемый, но он отправляет обещание в качестве значения для подписок. :(
Лаксмикант Данге
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 */);

Вы можете найти полную ссылку на оператор fromPromise здесь .

крестный отец
источник
47
import 'rxjs/add/observable/fromPromise';
Саймон Бриггс
16
import { Observable } from "rxjs/Observable"; :)
Счастливчик
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);
fridoo
источник
4
Я думаю, что разница - это капитал, спасибо за указание на это.
Старскрим
1

Вы также можете использовать Subject и вызывать его функцию next () из обещания. Смотрите образец ниже:

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

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
1

Вы также можете использовать отсрочку . Основное отличие заключается в том, что обещание не будет решаться или отказываться с нетерпением.

Матея Петрович
источник
0

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

  • Создание Lazy Observable с помощью оператора defer (), который позволяет создавать Observable только тогда, когда Observer подписывается.
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);
   }
)

Хизер
источник