私は最新の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つの方法を見つけることができました。
フルパイプ
this.service.getAll()
.pipe(
map((data) => this.onSuccess(data)),
catchError(error => of(this.handleError(error))),
finalize(() => this.stopLoading())
)
.subscribe();
ファイナライズにはパイプを使用する必要があるため、すべてにパイプを使用することもできます。すべてを同じ順序にする方が良いと思います。しかし、今では「of」と呼ばれるもの(非常に理解しにくい)をスローする必要があり、私はそれが好きではありません。
ハーフパイプそこで、別のアイデアを試します。必要なパイプのみ(ファイナライズ)を使用し、サブスクライブコールバックを保持します。
this.service.getAll()
.pipe(
finalize(() => this.stopLoading())
)
.subscribe(
(data) => this.onSuccess(data),
(error) => this.handleError(error)
);
しかしよく。少し後ろではないですか?まだ実際の名前のないコールバックがあり、処理とエラーを読み取る前に確定します。奇妙な。
ですから、私には絶対に理解できないことがあります。そして、この基本的な質問に関連するものはオンラインで見つけることができません。 「成功と最終」または「成功とエラー」を望んでいるが、誰もその3つを望んでいない人がいます。たぶん私は年を取りすぎており、それに関する新しいベストプラクティスを理解していません(もしそうなら、私を教育してください!)。
私のニーズは簡単です:
1。サービスから取得したデータを処理したい
2。ユーザーに表示するためにエラーを取得したい
3。呼び出しの前に開始したばかりの読み込みスピナーを停止するか、最初の呼び出しが完全に成功またはエラーになったら別の呼び出しを行います(最終的に欲しい)
Observableで基本的なHTTP呼び出しをどのように処理しますか?
(.toPromise
は必要ありません。新しいものの処理方法を理解したいです)
1つの重要な誤解があると思います。
「成功して最終的に」または「成功してエラー」を望んでいるが、3つを望んでいない人がいます。
これは完全に真実ではありません。各Observableは、0個以上のnext
通知と1つのerror
またはcomplete
通知を送信できますが、両方は送信できません。たとえば、成功したHTTP呼び出しを行う場合、1つのnext
と1つのcomplete
通知があります。エラーHTTPリクエストでは、error
通知が1つしかありません。それがすべてです。 http://reactivex.io/documentation/contract.html を参照してください
これは、error
とcomplete
の両方を出力するObservableが決してないことを意味します。
そして、finalize
演算子があります。この演算子は、チェーンを破棄するときに呼び出されます(プレーンな購読解除も含まれます)。つまり、aftererror
とcomplete
の両方の通知と呼ばれます。
したがって、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());
Observableのsubscribe
メソッドは、3つのオプション関数をパラメーターとして受け入れます
だから、私が正しく理解すれば、あなたが望むものはこのようなコードで達成することができます
this.service.getAll()
.subscribe(
data => this.onSuccess(data),
error => this.handleError(error),
() => this.onComplete()
);
Http呼び出しにObservablesを使用すると、(retry
演算子を使用して)競合状態が発生した場合に再試行(switchMap
演算子を参照)するときにメリットが得られることを考慮してください。これらが、Angularチームがhttpクライアントにこのアプローチを選択した主な理由だと思います。
一般的に言えば、Observablesと最も重要な演算子のいくつかを知ることから始める価値があると思います(上記のものに加えて、最初にmergeMap
、filter
、reduce
-ただし、ブラウザ(またはNodeなど)などの非同期の非ブロッキング環境で多くのタスクを大幅に簡素化できるため、他にも多数あります)は重要です。
正しい方法は、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が完全な機能をトリガーする方法の例にすぎません。ここから、必要なことを実行できます。