web-dev-qa-db-ja.com

Angular 6 / Rxjs-基本的な方法:オブザーバブルの成功、エラー、最後に

私は最新のAngular 6でアーキテクチャを構築していますが、AngularJSから来るのは、私が安心できないものです。HTTPリクエストの基本的な処理です。

それで、質問のために、私は観察可能なものが欲しいとしましょう。それはAngularの未来のようだからです。

私はAngularJSの非常にエレガントなものから始めました:

   service.getAll()
    .then(onSuccess) // I process the data
    .catch(onError) // I do whatever needed to notify anyone about the issue
    .finally(onFinally); // I stop the loading spinner and other stuff

Angular 6/RxJS 6では、なぜすべてがそれほど複雑で、正しくないのか理解できません。

上記と同じことを行う2つの方法を見つけることができました。

  1. フルパイプ

    this.service.getAll()
        .pipe(
            map((data) => this.onSuccess(data)),
            catchError(error => of(this.handleError(error))),
            finalize(() => this.stopLoading())
        )
        .subscribe();
    

ファイナライズにはパイプを使用する必要があるため、すべてにパイプを使用することもできます。すべてを同じ順序にする方が良いと思います。しかし、今では「of」と呼ばれるもの(非常に理解しにくい)をスローする必要があり、私はそれが好きではありません。

  1. ハーフパイプそこで、別のアイデアを試します。必要なパイプのみ(ファイナライズ)を使用し、サブスクライブコールバックを保持します。

    this.service.getAll()
    .pipe(
        finalize(() => this.stopLoading())
    )
    .subscribe(
        (data) => this.onSuccess(data),
        (error) => this.handleError(error)
    );
    

しかしよく。少し後ろではないですか?まだ実際の名前のないコールバックがあり、処理とエラーを読み取る前に確定します。奇妙な。

ですから、私には絶対に理解できないことがあります。そして、この基本的な質問に関連するものはオンラインで見つけることができません。 「成功と最終」または「成功とエラー」を望んでいるが、誰もその3つを望んでいない人がいます。たぶん私は年を取りすぎており、それに関する新しいベストプラクティスを理解していません(もしそうなら、私を教育してください!)。

私のニーズは簡単です:
1。サービスから取得したデータを処理したい
2。ユーザーに表示するためにエラーを取得したい
3。呼び出しの前に開始したばかりの読み込みスピナーを停止するか、最初の呼び出しが完全に成功またはエラーになったら別の呼び出しを行います(最終的に欲しい)

Observableで基本的なHTTP呼び出しをどのように処理しますか?

.toPromiseは必要ありません。新しいものの処理方法を理解したいです)

20
Simon Peyou

1つの重要な誤解があると思います。

「成功して最終的に」または「成功してエラー」を望んでいるが、3つを望んでいない人がいます。

これは完全に真実ではありません。各Observableは、0個以上のnext通知と1つのerrorまたはcomplete通知を送信できますが、両方は送信できません。たとえば、成功したHTTP呼び出しを行う場合、1つのnextと1つのcomplete通知があります。エラーHTTPリクエストでは、error通知が1つしかありません。それがすべてです。 http://reactivex.io/documentation/contract.html を参照してください

これは、errorcompleteの両方を出力するObservableが決してないことを意味します。

そして、finalize演算子があります。この演算子は、チェーンを破棄するときに呼び出されます(プレーンな購読解除も含まれます)。つまり、aftererrorcompleteの両方の通知と呼ばれます。

したがって、2番目の例は正しいです。サブスクライブする前にfinalizeを含めるのは奇妙に見えますが、実際には、ソースObservableからの各エミッションは、最初に上から下へ、サブスクライバーに到達し、errorまたはcomplete通知の場合破棄ハンドラをボトムアップで(逆の順序で)トリガーし、この時点でfinalizeが呼び出されます。 https://github.com/ReactiveX/rxjs/blob/master/src/internal/Subscriber.ts#L150-L152 を参照してください

あなたの例では、finalizeを使用することは、Subscriptionオブジェクトに自分で破棄ハンドラーを追加することと同じです。

const subscription = this.service.getAll()
  .subscribe(
    (data) => this.onSuccess(data),
    (error) => this.handleError(error)
  );

subscription.add(() => this.stopLoading());
24
martin

Observableのsubscribeメソッドは、3つのオプション関数をパラメーターとして受け入れます

  • observableによって発生したイベントに付随するデータを処理する最初のもの
  • エラーが発生した場合にエラーを処理する2番目
  • observableの完了時に何かをする3番目の

だから、私が正しく理解すれば、あなたが望むものはこのようなコードで達成することができます

this.service.getAll()
.subscribe(
    data => this.onSuccess(data),
    error => this.handleError(error),
    () => this.onComplete()
);

Http呼び出しにObservablesを使用すると、(retry演算子を使用して)競合状態が発生した場合に再試行(switchMap演算子を参照)するときにメリットが得られることを考慮してください。これらが、Angularチームがhttpクライアントにこのアプローチを選択した主な理由だと思います。

一般的に言えば、Observablesと最も重要な演算子のいくつかを知ることから始める価値があると思います(上記のものに加えて、最初にmergeMapfilterreduce-ただし、ブラウザ(またはNodeなど)などの非同期の非ブロッキング環境で多くのタスクを大幅に簡素化できるため、他にも多数あります)は重要です。

5
Picci

正しい方法は、Observable関数を使用することだと思います:next、err、complete。
完全な機能をトリガーする方法の例を次に示します。
BehaviorSubjectオブジェクトがあるとします。

let arr = new BehaviorSubject<any>([1,2]);

ここで、サブスクライブしたいと仮定し、値「finish」を取得したら完了したいとします。

let arrSubscription = arr.asObservable().subscribe(
  data => {
      console.log(data)
      if(data === 'finish') {
        arr.complete()
      }
  },
  err => {
      console.log(err)
  },
  () => {
      console.log("Complete function triggered.")
  }
);
arr.next([3,4])
arr.next('finish')
arr.next([5,6])

コンソールログは次のとおりです。

[1,2]
[3,4]
finish
Complete function triggered.

完全な関数をトリガーしたので、errとcomplete関数はサブスクリプションのターミネーターであるため、BehaviorSubjectの最後の.nextが起動しません。
これは、uが完全な機能をトリガーする方法の例にすぎません。ここから、必要なことを実行できます。

1
dAxx_