[解決済み] プロミスチェインで複数のキャッチを処理する
質問
私はまだプロミスの初心者で、現在ブルーバードを使用していますが、あるシナリオがあり、それにどのように対処するのがベストかよくわかりません。
例えば、私はexpressアプリの中で次のようなプロミスチェーンを持っています。
repository.Query(getAccountByIdQuery)
.catch(function(error){
res.status(404).send({ error: "No account found with this Id" });
})
.then(convertDocumentToModel)
.then(verifyOldPassword)
.catch(function(error) {
res.status(406).send({ OldPassword: error });
})
.then(changePassword)
.then(function(){
res.status(200).send();
})
.catch(function(error){
console.log(error);
res.status(500).send({ error: "Unable to change password" });
});
ということで、私が求めている動作は
- IDでアカウントを取得しに行く
- この時点で拒否された場合、ボムアウトしてエラーを返す
- エラーがない場合、返されたドキュメントをモデルに変換します。
- データベースのドキュメントでパスワードを確認する
- パスワードが一致しない場合、ボムアウトして別のエラーを返します。
- エラーがない場合は、パスワードを変更します。
- その後、成功を返す
- 何か問題があった場合は、500を返す
現在、catch は連鎖を止めないようで、それは理にかなっています。そこで、エラーに基づいてある時点で連鎖を強制的に止める方法があるかどうか、あるいは、ある形式の分岐動作を得るためにこれを構造化する良い方法があるかどうか、例えば
if X do Y else Z
.
何か手助けがあれば幸いです。
どのように解決するのですか?
この動作はまさにsynchronous throwのようなものです。
try{
throw new Error();
} catch(e){
// handle
}
// this code will run, since you recovered from the error!
のポイントの半分はそこです。
.catch
- の目的の半分は、エラーから回復することができるようにすることです。状態がまだエラーであることを知らせるためにrethrowすることが望ましいかもしれません。
try{
throw new Error();
} catch(e){
// handle
throw e; // or a wrapper over e so we know it wasn't handled
}
// this code will not run
しかし、これだけでは、エラーが後のハンドラによって捕捉されるため、あなたのケースではうまくいきません。ここでの本当の問題は、一般化された "HANDLE ANYTHING" エラーハンドラは一般的に悪い習慣であり、他のプログラミング言語やエコシステムでは非常に嫌われるものだということです。このため、Bluebirdは型付きキャッチと述語キャッチを提供しています。
追加の利点は、ビジネスロジックがリクエスト/レスポンスサイクルを全く意識する必要がない(べきではない)ことです。クライアントがどのHTTPステータスとエラーを取得するかを決めるのはクエリの責任ではありませんし、アプリが成長するにつれて、ビジネスロジック(DBへの問い合わせ方法とデータの処理方法)とクライアントに送るもの(どのHTTPステータスコード、どのテキスト、どの応答)を分離したいと思うかもしれません。
以下は、私がコードを書く方法です。
まず、私は
.Query
を投げるようにします。
NoSuchAccountError
からサブクラス化します。
Promise.OperationalError
をサブクラス化します。もし、エラーのサブクラス化の方法がわからなければ、私に教えてください。
をサブクラス化すると、さらに
AuthenticationError
というようなことをします。
function changePassword(queryDataEtc){
return repository.Query(getAccountByIdQuery)
.then(convertDocumentToModel)
.then(verifyOldPassword)
.then(changePassword);
}
見ての通り - とてもきれいで、プロセスで何が起こるかの取扱説明書のようなテキストを読むことができます。また、リクエスト/レスポンスから分離されています。
さて、このようにルートハンドラから呼び出します。
changePassword(params)
.catch(NoSuchAccountError, function(e){
res.status(404).send({ error: "No account found with this Id" });
}).catch(AuthenticationError, function(e){
res.status(406).send({ OldPassword: error });
}).error(function(e){ // catches any remaining operational errors
res.status(500).send({ error: "Unable to change password" });
}).catch(function(e){
res.status(500).send({ error: "Unknown internal server error" });
});
こうすることで、ロジックはすべて一箇所に集まり、クライアントへのエラー処理の判断も一箇所に集まり、互いに混乱することがありません。
関連
-
fetch ネットワークリクエストラッパーの説明例
-
Vue Element-uiは、アイコンを追加するためのツリーコントロールノードを詳細に実装しています。
-
WeChatアプレット用ユニアプリによるグローバルシェアリング
-
Vueにシンプルなメモ帳機能を実装
-
[解決済み】gulp anythingを実行するたびに、アサーションエラーが発生します。- タスク関数を指定する必要があります
-
[解決済み] Node.jsの例外処理のベストプラクティス
-
[解決済み] 明示的なプロミス構築のアンチパターンとそれを回避する方法とは?
-
[解決済み] オブジェクトがPromiseであるかどうかを判断するにはどうすればよいですか?
-
[解決済み] .then()チェーンで以前のプロミス結果にアクセスするにはどうすればよいですか?
-
[解決済み] 約束の連鎖を切断し、切断された連鎖のステップに応じた関数を呼び出す(拒否)
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
元のイベントが実行されなかった後に要素を追加するためのjQueryソリューション
-
vue+webrtc(Tencent cloud)ライブ機能の実践を実現するために
-
vueの補間表現とv-textディレクティブの違いについて
-
Vueのクラススタイルの使い方の詳細
-
vueにおけるfilterの適用シーンについて解説します。
-
[解決済み】Node.js getaddrinfo ENOTFOUND
-
[解決済み] 配列の結合時に未定義のプロパティ 'push' を読み込むことができない
-
[解決済み】TypeScript-のAngular Frameworkエラー - "exportAsがngFormに設定されたディレクティブはありません"
-
OSSアップロードエラーを解決する: net::ERR_SSL_PROTOCOL_ERROR
-
[解決済み】JavaScriptでスクリプトを終了させる方法は?