TypeScriptやECMAScriptなどの最新バージョンの言語では、async
/await
構造を使用して、同期プログラミングのクリーンな構造と非同期コードのパフォーマンス上の利点を組み合わせたコードを記述できます。
これを例として取り上げます。
async function isAdmin() {
// Async IO request...
return false;
}
async function doSomething() {
if (await isAdmin()) {
console.log("Done");
} else throw new Error("Unauthorized");
}
doSomething();
とてもきれいに見えます。ただし、コードの同期的な外観のため、関数の呼び出しでawait
を忘れることはそれほど難しくありません。したがって、次のように記述します。
// ...
if (isAdmin()) {
console.log("Done");
} else throw new Error("Unauthorized");
これは危険なほど間違っています。
デフォルトですべての非同期関数を待機し、プログラマーに非同期で実行する操作を選択させる代わりに、この選択の背後にある理論的根拠は何ですか?この構成された構文のようなもの:
var admin = isAdmin(); // wait isAdmin to return a result
async doSomething(); // call doSomething asynchronously
doSomething(); // call doSomething synchronously
var promise = async doSomething(); // Get the underlying Promise
async
である関数は、それを完全に異なるものに変えるのではなく、いくつかの構文を有効にするだけであることに注意してください。 promiseを返す通常の関数は、async
でマークされた関数と同じように非同期です。
await
は、「その間に世界が変わった可能性がある」という警告サインとして機能します。
await
はマルチスレッドよりも簡単かもしれませんが、それでも非常にエラーが発生しやすくなります。コードレビュー中に、各await
を調べて、「関数はawait
がまだ同じになる前に取得した情報に依存していますか?これは保証されていますか?」と考える必要があります。明示的なawait
がない場合は、関数を呼び出すたびにそうする必要があります。
async
を挿入する必要があります。if result is a promise then await
チェックを挿入する必要があります。すべての関数を待ちたくない場合があるため。一部の関数を同期的に実行する場合があります。
あなたの例は「危険なほど間違っている」のではなく、単に同期しているだけです。
ちなみに、isAdmin()
という名前の関数をawait
する必要はありません。とにかくほぼすぐに返されるはずです。また、if
ステートメントは続行する前に戻り結果を必要とするため、非同期で実行されることすらありません。
1つではなく2つのキーワードが使用される理由については、 Async DunctionsのTypeScript提案 で説明されています。
非同期関数は、JavaScript関数、パラメーター化された矢印関数、メソッド、またはGet Accessorであり、接頭辞として
async
修飾子が付いています。この修飾子は、関数本体の転置が必要であり、キーワードawait
を識別子ではなく単項式として扱う必要があることをコンパイラーに通知します。