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

Наблюдаемые в HTTP и коллекциях кажутся простыми. Как я могу преобразовать что-то подобное в наблюдаемый образец.

Это из моего служебного компонента для аутентификации. Я бы предпочел, чтобы это работало так же, как и другие HTTP-сервисы в Angular2 - с поддержкой обработчиков данных, ошибок и завершения.

firebase.auth (). CreateUserWithEmailAndPassword (электронная почта, пароль)
  .then (функция (firebaseUser) {
    // делаем что-нибудь для обновления вашего UI-компонента
    // передаем объект пользователя в компонент пользовательского интерфейса
  })
  .catch (функция (ошибка) {
    // Здесь обрабатываются ошибки.
    var errorCode = error.code;
    var errorMessage = error.message;
    // ...
  });

Любая помощь здесь будет очень признательна. Единственным альтернативным решением, которое у меня было, было создание EventEmitters. Но я думаю, что это ужасный способ делать что-то в разделе услуг

Ответы (9)

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

импорт {from} из 'rxjs';
const наблюдаемый = от (обещание);

1 Прямое выполнение / преобразование

Используйте из, чтобы напрямую преобразовать ранее созданное обещание в наблюдаемое.

импорт {from} из 'rxjs';

// getPromise () вызывается один раз, обещание передается в Observable
const наблюдаемый $ = from (getPromise ());

observable $ будет hot Observable, который эффективно воспроизводит значение Promises для подписчиков.

Это популярный Observable, потому что производитель (в данном случае Promise) создается вне Observable. Несколько подписчиков будут использовать одно и то же обещание. Если внутреннее обещание было разрешено, новый подписчик на Observable немедленно получит его значение.

2 отложенного исполнения при каждой подписке

Используйте defer с фабричной функцией Promise в качестве входных данных, чтобы отложить создание и преобразование Promise в Observable.

импорт {отложить} из 'rxjs';

// getPromise () вызывается каждый раз, когда кто-то подписывается на наблюдаемый $
const наблюдаемый $ = defer (() => getPromise ());

наблюдаемый $ будет холодным Наблюдаемым.

Это холодный Observable, потому что производитель (Promise) создается внутри Observable. Каждый подписчик будет создавать новое обещание, вызывая заданную функцию фабрики обещаний.

Это позволяет вам создать наблюдаемый $ без создания и, таким образом, немедленного выполнения обещания и без совместного использования этого обещания с несколькими подписчиками. Каждый подписчик на observable $ фактически вызывает из (promiseFactory ()). Subscribe (подписчик). Таким образом, каждый подписчик создает и преобразует свое собственное новое обещание в новый Observable и присоединяется к этому новому Observable.

3 Многие операторы принимают обещания напрямую

Большинство операторов RxJS, которые объединяют (например, merge, concat, forkJoin, combLatest ...) или преобразуют наблюдаемые (например,switchMap, mergeMap, concatMap, catchError ...) принимайте обещания напрямую. Если вы все равно используете один из них, вам не нужно использовать from, чтобы сначала обернуть обещание (но для создания холодного наблюдаемого вам все равно, возможно, придется использовать отложить).

// Выполняем два обещания одновременно
forkJoin (getPromise (1), getPromise (2)). pipe (
  switchMap (([v1, v2]) => v1.getPromise (v2)) // отображение на вложенное обещание
)

Проверьте документацию или реализацию, чтобы узнать, принимает ли используемый вами оператор ObservableInput или SubscribableOrPromise.

тип ObservableInput  = SubscribableOrPromise  | ArrayLike  | Iterable ;
// Обратите внимание на PromiseLike --------------------------------------------- ------- v
type SubscribableOrPromise  = Subscribable  | Подписка <никогда> | PromiseLike  | InteropObservable ;

Разница между от и defer в примере: https://stackblitz.com/edit/rxjs-6rb7vf

const getPromise = val => new Promise (resolve => {
  console.log ('Обещание создано для', val);
  setTimeout (() => resolve (`Обещание выполнено: $ {val}`), 5000);
});

// выполнение getPromise ('FROM') начинается здесь, когда вы создаете обещание внутри из
const fromPromise $ = from (getPromise ('FROM'));
const deferPromise $ = defer (() => getPromise ('DEFER'));

fromPromise $ .subscribe (console.log);
// выполнение getPromise ('DEFER') начинается здесь, когда вы подписываетесь на deferPromise $
deferPromise $ .subscribe (console.log);

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

импорт {from} из 'rxjs';

from (firebase.auth (). createUserWithEmailAndPassword (электронная почта, пароль))
.subscribe ((пользователь: любой) => {
      console.log ('тест');
});

Вот более короткая версия, в которой используется комбинация некоторых из приведенных выше ответов для преобразования вашего кода из обещания в наблюдаемое.

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

  • Создание Lazy Observable с использованием оператора defer (), который позволяет создавать Observable только при подписке Observer.
import { of, Observable, defer } from 'rxjs'; 
import { map } from 'rxjs/operators';


function getTodos$(): Observable {
  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);
   }
)

Существует оператор toPromise (), предоставляемый Rxjs, Как показывает пример кода:

@Injectable({
  providedIn: 'root'
})
export class InventoryService {
  constructor(private httpClient: HttpClient) {}

  getCategories(): Observable {
    const url = 'https://www.themealdb.com/api/json/v1/1/categories.php';

    return this.httpClient.get(url).pipe(
      map(response => response.categories)
    );
  }
}

А внутри вашего компонента вы можете применить оператор toPromise ():

export class AppComponent {
  categories: any[];

  constructor(private inventoryService: InventoryService) {}

  public async loadCategories() {
    this.categories = await this.inventoryService
      .getCategories()
      .**toPromise()**

Но в настоящее время Rxjs7 + устарел, и рекомендуется использовать lastValueFrom () оператор:

  public async loadCategories() {
    const categories$ = this.inventoryService.getCategories();
    this.categories = await **lastValueFrom**(categories$);
  }

Надеюсь с обновленным кодом с обновленной версией поможет: ')

try this:

import 'rxjs / add / observable / fromPromise';
импортировать {Observable} из "rxjs / Observable";

const subscription = Observable.fromPromise (
    firebase.auth (). createUserWithEmailAndPassword (электронная почта, пароль)
);
subscription.subscribe (firebaseUser => / * Что-нибудь делать с полученными данными * /,
                       error => / * Здесь обрабатывается ошибка * /);

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

Правильный шаблон для преобразования обещания в наблюдаемое использует операторы defer и from:

импорт {отложить, из} из 'rxjs';
    
const наблюдаемый $ = defer (() => from (myPromise ()));

Зачем нужен оператор defer?

Обещания - это нетерпеливые, это означает, что при вызове они срабатывают мгновенно. Это противоположно тому, как работают наблюдаемые. Observables - это lazy, они запускаются только при вызове .subscribe (). По этой причине нам нужно всегда заключать его в оператор defer. Оператор from не выполняет этой работы, поэтому defer is всегда необходим.

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

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

class UserService {
  частный createUserSubject: Subject <любой>;

  createUserWithEmailAndPassword () {
    if (this.createUserSubject) {
      вернуть this.createUserSubject;
    } еще {
      this.createUserSubject = новый субъект <любой> ();
      firebase.auth (). createUserWithEmailAndPassword (электронная почта,
          пароль)
        .then (функция (firebaseUser) {
          // делаем что-нибудь для обновления вашего UI-компонента
          // передаем пользовательский объект в компонент пользовательского интерфейса
          this.createUserSubject.next (firebaseUser);
        })
        .catch (функция (ошибка) {
          // Здесь обрабатываются ошибки.
          var errorCode = error.code;
          var errorMessage = error.message;
          this.createUserSubject.error (ошибка);
          // ...
        });
    }

  }
}

Создать пользователя из компонента, как показано ниже

класс UserComponent {
  constructor (private userService: UserService) {
    this.userService.createUserWithEmailAndPassword (). подписаться (пользователь => console.log (пользователь), ошибка => console.log (ошибка);
    }
  }

2022 WebDevInsider