プロミスを観察可能なものに変換


214

オブザーバブルに頭を抱えようとしています。オブザーバブルが開発と可読性の問題を解決する方法が大好きです。私が読んだように、利益は計り知れません。

HTTPおよびコレクションのオブザーバブルは簡単なようです。このようなものを観測可能なパターンに変換するにはどうすればよいですか。

これは、認証を提供するための私のサービスコンポーネントからのものです。これは、Angular2の他のHTTPサービスのように機能することを好みます-データ、エラー、および完了ハンドラーをサポートします。

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 を作成することでした。しかし、それはサービスセクションで物事を行うためのひどい方法だと思います

回答:


315

RxJS 6.0.0を使用している場合:

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

9
6.3.3を使用すると、fromメソッドは監視可能を返しますが、サブスクリプションに値としてpromiseを送信しています。:(
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 */);

fromPromise演算子への完全な参照は、こちらで確認できます。


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

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

40

1直接実行/変換

from以前に作成されたプロミスをオブザーバブルに直接変換するために使用します。

import { from } from 'rxjs';

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

observable$加入者への約束の値を効果的に再生するホットなオブザーバブルになります。

promised bodyは実行中か、オブザーバブルが作成されたときにすでに解決されています。内部の約束が解決された場合、オブザーバブルの新しいサブスクライバーはすぐにその値を取得します。

2サブスクライブごとの遅延実行

deferpromiseファクトリ関数を入力として使用して、promiseの作成とオブザーバブルへの変換を延期します。

import { defer } from 'rxjs';

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

observable$なります寒い観察できます

との違いfromdefer、サブスクライバーを待機してから、指定されたpromiseファクトリー関数を呼び出して新しいpromiseを作成することです。これは、オブザーバブルを作成したいが、内部のプロミスをすぐに実行したくない場合に役立ちます。インナープロミスは、誰かがオブザーバブルをサブスクライブしたときにのみ実行されます。各サブスクライバーは、独自の新しいオブザーバブルも取得します。

3多くのオペレーターが約束を直接受け入れる

コンバインほとんどRxJS事業者(例えばmergeconcatforkJoincombineLatest...)、または(例えば観測変換switchMapmergeMapconcatMapcatchError...)直接約束を受け入れます。とにかくそれらのいずれかを使用fromしている場合は、最初にpromiseをラップするために使用する必要はありません(ただし、コールドオブザーバブルを作成するために、まだ使用する必要がある場合があります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>;

fromdeferの例の違い: 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

サブジェクトを使用して、そのnext()関数をpromiseからトリガーすることもできます。以下のサンプルを参照してください。

以下のようなコードを追加します(私はサービスを使用しました)

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 2018

私はただ解決策を与えています。
Shivang Gupta

あなたは少なくともnew Observable(observer => { ... observer.next() ... })それを実装する方法を示すことができます。これは既存の既知の機能を再実装したものですが、質問に直接回答するため、読者に害はありません。
polkovnikov.ph 2018


0

promise機能の周りにラッパーを追加して、Observableをオブザーバーに返すことができます。

  • オブザーバーがサブスクライブするときにのみオブザーバブルを作成できるようにする、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);
   }
)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.