ES2017 async/awaitの優れたパターンは次のとおりです。
async function () {
try {
var result = await some_promised_value()
} catch (err) {
console.log(`This block would be processed in
a reject() callback with promise patterns
but this is far more intuitive`)
return false // or something less obtuse
}
result = do_something_to_result(result)
return result;
}
そのようなエラーを処理できることは本当に素晴らしいことです。しかし、再割り当てから保護したい値(データベースセッションなど)を非同期で取得したいが、それでも非同期/待機パターンを使用したいとします(これははるかに直感的だと思うので)。
Constはブロックスコープであるため、以下は機能しません。
async function () {
try {
const result = await get_session()
} catch (err) {
console.log(`This block should catch any
instantiation errors.`)
return false
}
// Can't get at result here because it is block scoped.
}
もちろん、try
ブロック内で関数の残りの部分を実行することはできますが、エラーが発生して他の場所に移動する危険性があります。 (たとえば、テストの失敗などのエラーがテストスイートにフォールバックする必要があるが、ドライバーのインスタンス化を自分で処理したいというテストを作成するこの課題に挑戦しました。おそらく、これらのエラーをフォールバックさせないことによって、ここで何らかのアンチパターンに陥っています。テストスイートに。)
単純な答えは明らかに、ここではそのパターンを使用しないことです。代わりにPromiseとコールバックを使用してください。または、var
を使用して、ブロックスコープのconst
およびlet
を回避します。しかし、私は他の考慮事項に対して再割り当て保護とブロックスコープの利点を気に入っています。
[質問]: await/async try/catchブロックをすべての関数にラップする方法はありますか? 解決策の1つと思われますが、try/catch
ほど読みやすいとは言えません。 try/catch
は関数のスコープを壊さず、try/catch
ブロック内からreturn
を使用できるという事実は、async/await
の精神に沿っており、非同期コードに手続き型のロジックを提供しているようです。
理想的には、const x = await y() catch (err)
またはconst x = await y() || fail
のようなものを実行する必要がありますが、構文的に正しい同様のフローを持つものは考えられません。
更新:@ jmar777が提案する別の代替案は次のとおりです。
const x = await y().catch(() => {/*handle errors here*/})
これはおそらく、私が見つけた最後の2つの例に最も近いものです。しかし、上記の例でダウンストリームの実行をブロックするreturn
スコープを壊します。これは、同期に似た方法で処理する方法です。
各ソリューションにはトレードオフがあります。
関数ブロックの先頭にあるlet
を使用して手動で変数を引き上げましたが(jmar777の回答で説明されているように)、さまざまなアプローチを見るのに興味深い質問なので、今は質問を開いたままにしておきます。
数年後にこの質問に戻ると、はるかに単純な答えが私に起こりました、なぜ私が小さなtry/catchペアに興味があり、単純にすべてを実行できるのに、その外側でより多くのロジックを実行したのか振り返ってみませんロジックとtryステートメント内に戻ります。
質問から例を取り、その構造を適用すると、次のようになります。
async function () {
try {
const result = await get_session()
// Do what needs to be done and then:
return result
} catch (err) {
console.log(`This block should catch any
instantiation errors.`)
return false
}
}
Catchブロックのtryブロックから何かにアクセスする必要がある場合は、エラーで発生させます。この質問をしたときにtryスコープの外に移動する必要があった理由はあるかもしれませんが、振り返ってみる必要があるシナリオがわかりません。このソリューションは、try/catch/finallyを使用して、最終的に戻る場合には機能しません。しかし、実際にそのパターンに遭遇したことはほとんどないと思います。
const
を使用する利点について誤解しているかもしれません。 const
宣言を使用して値を割り当てても、その値は不変になりません。単に、その定数の値を変更または再宣言できないことを意味します。
Const宣言は、値への読み取り専用の参照を作成します。それが保持する値が不変であることを意味するのではなく、変数識別子を再割り当てできないということだけです。たとえば、コンテンツがオブジェクトの場合、これはオブジェクト自体を変更できることを意味します。 ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const )
あなたの例では、おそらく、try/catchの外でresult
バインディングを手動で巻き上げるのが最善でしょう。
_async function () {
let result;
try {
result = await get_session()
} catch (err) {
console.log(`This block should catch any
instantiation errors.`)
}
// do whatever else you need with result here...
}
_
別の方法は、try/catchにまったく依存する必要がないようにコードを再構成することです。例えば:
_async function () {
const result = await get_session().catch(someRejectionHandler);
// do whatever else you need with result here...
}
_
ダウンストリームコードは、get_session()
が拒否され、正常な応答に基づいてresult
が初期化されない場合を適切に処理する必要があることに注意してください。これは最初の例と同じですが、コードをスキャンするときにそれほど明白ではないかもしれません。