私はまだ約束にかなり慣れておらず、現在bluebirdを使用していますが、それをどのように処理するのが最善かわからないシナリオがあります。
たとえば、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" });
});
したがって、私が求めている動作は次のとおりです。
ですから、現在の漁獲量は連鎖を止めていないようで、それは理にかなっているので、エラーに基づいてチェーンを特定の時点で強制的に停止させる方法があるのか、それとももっと良い方法があるのか疑問に思います。の場合があるように、これを構造化して、何らかの形の分岐動作を取得しif X do Y else Z
ます。
どんな助けでも素晴らしいでしょう。
この動作は、同期スローとまったく同じです。
try{
throw new Error();
} catch(e){
// handle
}
// this code will run, since you recovered from the error!
これは、.catch
エラーから回復できるようにするためのポイントの半分です。状態がまだエラーであることを通知するために、再スローすることが望ましい場合があります。
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ステータスコード、どのテキスト、どの応答)。
これが私があなたのコードを書く方法です。
まず、Bluebirdがすでに提供しているサブクラス.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" });
});
このように、ロジックはすべて1つの場所にあり、クライアントへのエラーを処理する方法の決定はすべて1つの場所にあり、それらは互いに乱雑になりません。
.catch
try-catch
ステートメントのように機能します。つまり、最後に1つのキャッチのみが必要です。
repository.Query(getAccountByIdQuery)
.then(convertDocumentToModel)
.then(verifyOldPassword)
.then(changePassword)
.then(function(){
res.status(200).send();
})
.catch(function(error) {
if (/*see if error is not found error*/) {
res.status(404).send({ error: "No account found with this Id" });
} else if (/*see if error is verification error*/) {
res.status(406).send({ OldPassword: error });
} else {
console.log(error);
res.status(500).send({ error: "Unable to change password" });
}
});
エラーに基づいて、チェーンを特定のポイントで強制的に停止させる方法があるかどうか疑問に思っています
いいえ。チェーンの最後までバブルする例外をスローしない限り、チェーンを実際に「終了」することはできません。その方法については、BenjaminGruenbaumの回答を参照してください。
彼のパターンの導出は、エラーの種類を区別しますが、持っていたエラーを使用していないだろうstatusCode
し、body
単一の汎用から送ることができるフィールド.catch
ハンドラを。ただし、アプリケーションの構造によっては、彼のソリューションの方がクリーンな場合があります。
または、これを構造化して何らかの形の分岐動作を取得するためのより良い方法がある場合
はい、promiseを使用して分岐を行うことができます。ただし、これは、チェーンを離れてネストに「戻る」ことを意味します。ネストされたif-elseまたはtry-catchステートメントで行うのと同じです。
repository.Query(getAccountByIdQuery)
.then(function(account) {
return convertDocumentToModel(account)
.then(verifyOldPassword)
.then(function(verification) {
return changePassword(verification)
.then(function() {
res.status(200).send();
})
}, function(verificationError) {
res.status(406).send({ OldPassword: error });
})
}, function(accountError){
res.status(404).send({ error: "No account found with this Id" });
})
.catch(function(error){
console.log(error);
res.status(500).send({ error: "Unable to change password" });
});
私はこのようにしてきました:
あなたは最後にあなたのキャッチを残します。そして、チェーンの途中でエラーが発生したときにエラーをスローします。
repository.Query(getAccountByIdQuery)
.then((resultOfQuery) => convertDocumentToModel(resultOfQuery)) //inside convertDocumentToModel() you check for empty and then throw new Error('no_account')
.then((model) => verifyOldPassword(model)) //inside convertDocumentToModel() you check for empty and then throw new Error('no_account')
.then(changePassword)
.then(function(){
res.status(200).send();
})
.catch((error) => {
if (error.name === 'no_account'){
res.status(404).send({ error: "No account found with this Id" });
} else if (error.name === 'wrong_old_password'){
res.status(406).send({ OldPassword: error });
} else {
res.status(500).send({ error: "Unable to change password" });
}
});
他の関数はおそらく次のようになります。
function convertDocumentToModel(resultOfQuery) {
if (!resultOfQuery){
throw new Error('no_account');
} else {
return new Promise(function(resolve) {
//do stuff then resolve
resolve(model);
}
}
おそらくパーティーに少し遅れますが、.catch
ここに示すようにネストすることは可能です:
Mozilla DeveloperNetwork-Promisesの使用
編集:一般的に求められている機能を提供するため、これを提出しました。ただし、この特定のケースではそうではありません。すでに他の人が詳細に説明しているように.catch
、エラーを回復することになっているからです。たとえば、明示的なものがない場合はそれを解決するため、複数の .catch
コールバックでクライアントに応答を送信することはできません。その場合、チェーンが実際に解決されていなくてもトリガーが続行され、フォローがトリガーされて送信される可能性があります。クライアントへの別の応答。エラーを引き起こし、おそらくあなたの道を投げます。この複雑な文章があなたにとって意味のあるものであることを願っています。.catch
return
undefined
.then
.catch
UnhandledPromiseRejection
.then().catch()...
あなたの代わりに行うことができます.then(resolveFunc, rejectFunc)
。この約束の連鎖は、途中で物事を処理した方がよいでしょう。これが私がそれを書き直す方法です:
repository.Query(getAccountByIdQuery)
.then(
convertDocumentToModel,
() => {
res.status(404).send({ error: "No account found with this Id" });
return Promise.reject(null)
}
)
.then(
verifyOldPassword,
() => Promise.reject(null)
)
.then(
changePassword,
(error) => {
if (error != null) {
res.status(406).send({ OldPassword: error });
}
return Promise.Promise.reject(null);
}
)
.then(
_ => res.status(200).send(),
error => {
if (error != null) {
console.error(error);
res.status(500).send({ error: "Unable to change password" });
}
}
);
注:これif (error != null)
は、最新のエラーを処理するためのちょっとしたハックです。
上記のBenjaminGruenbaumの答えは、複雑な論理シーケンスの最良の解決策だと思いますが、これがより単純な状況に対する私の代替案です。私はちょうど使用errorEncountered
と一緒に旗をreturn Promise.reject()
後続スキップするthen
かcatch
の文を。したがって、次のようになります。
let errorEncountered = false;
someCall({
/* do stuff */
})
.catch({
/* handle error from someCall*/
errorEncountered = true;
return Promise.reject();
})
.then({
/* do other stuff */
/* this is skipped if the preceding catch was triggered, due to Promise.reject */
})
.catch({
if (errorEncountered) {
return;
}
/* handle error from preceding then, if it was executed */
/* if the preceding catch was executed, this is skipped due to the errorEncountered flag */
});
2つ以上のthen / catchペアがある場合は、おそらくBenjaminGruenbaumのソリューションを使用する必要があります。しかし、これは簡単なセットアップで機能します。
スキップする必要のある後続がないため、ファイナルにcatch
はではreturn;
なくのみがあることに注意してください。これは、ノードが好まない未処理のPromise拒否としてカウントされます。上に書かれているように、決勝戦は平和的に解決された約束を返します。return Promise.reject();
then
catch
Reba McEntire が息子の Shelby Blackstock と共有しているクリスマスの伝統について学びましょう。
メーガン・マークルとマライア・キャリーが自然な髪の上でどのように結合したかについて、メーガンの「アーキタイプ」ポッドキャストのエピソードで学びましょう.
ハリー王子が家族、特にチャールズ王とウィリアム王子との関係について望んでいると主張したある情報源を発見してください。
ワイノナ・ジャッドが、母親のナオミ・ジャッドが亡くなってから初めての感謝祭のお祝いを主催しているときに、彼女が今では家長であることをどのように認識したかを学びましょう.
Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?
The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!
爪| $ 15 | マルボロ&ケインザクロー| $ 15 | Malboro&Kane世界最小のマルチツールであるTheClawをたった15ドルで手に入れましょう。男の子と一緒に冷たいものを割って開けたり、ネジを締めたり、Amazonパッケージを細断したりする場合でも、この悪い男の子はこれまでで最も便利な製品の1つです。
人が2つのマッチを接着するように導くものは何ですか?何があなたをマッチに打ち続け、構造が湾曲していることを発見するのですか?42,000のボールを作るまで、試合を続けなければならない理由は何ですか?しかし、何よりも、これほど魅力的なショーである可能性はどのようにありますか?私はあなたをだますつもりはありません、次に私たちがあなたに残すのは、あなたや私のような人が自由な時間を過ごすことを決定するビデオですボールを作るために必要な試合数を確認します(答えは42です。
写真:AP先月、カリフォルニアの地元新聞が1,900万件以上の有権者記録をオンラインで公開しました。Gizmodoは今週、明らかなランサムウェア攻撃中にレコードが侵害されたことを確認しました。
ロシアのフィギュアスケーター、カミラ・バリエバが関与したドーピング事件が整理されているため、チームは2022年北京冬季オリンピックで獲得したメダルを待っています。
何千人ものAmazonの買い物客がMulberry Silk Pillowcaseを推奨しており、現在販売中. シルクの枕カバーにはいくつかの色があり、髪を柔らかく肌を透明に保ちます。Amazonで最大46%オフになっている間にシルクの枕カバーを購入してください
ラファイエット警察署は、「不審な男性が女性に近づいた」という複数の苦情を受けて、12 月にパデュー大学の教授の捜査を開始しました。
私たちの周りの世界と同じように、言語は常に変化しています。以前の時代では、言語の変化は数年または数十年にわたって発生していましたが、現在では数日または数時間で変化する可能性があります。
認知症を患っている 91 歳のアジア人女性が最近、47 番街のアウター サンセット地区でロメオ ロレンゾ パーハムに襲われました。伝えられるところによると、被害者はサンフランシスコの通りを歩いていたところ、容疑者に近づき、攻撃を受け、暴行を受けました。
“And a river went out of Eden to water the garden, and from thence it was parted and became into four heads” Genesis 2:10. ? The heart is located in the middle of the thoracic cavity, pointing eastward.
人々にチャンスを与えることは、人生で少し遅すぎると私は信じています。寛大に。