web-dev-qa-db-ja.com

Promiseがデフォルトで「待機」されないのはなぜですか?

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
1
danieleds

asyncである関数は、それを完全に異なるものに変えるのではなく、いくつかの構文を有効にするだけであることに注意してください。 promiseを返す通常の関数は、asyncでマークされた関数と同じように非同期です。

  1. awaitは、「その間に世界が変わった可能性がある」という警告サインとして機能します。

    awaitはマルチスレッドよりも簡単かもしれませんが、それでも非常にエラーが発生しやすくなります。コードレビュー中に、各awaitを調べて、「関数はawaitがまだ同じになる前に取得した情報に依存していますか?これは保証されていますか?」と考える必要があります。明示的なawaitがない場合は、関数を呼び出すたびにそうする必要があります。

  2. 下位互換性。ブラウズ/ランタイムが待機をサポートしているかどうかにかかわらず、プロポーザルコードの動作は完全に異なります。
  3. コードが待機を処理したくない場合は、promiseが返される場合に備えて、外部で定義された関数を呼び出すたびにasyncを挿入する必要があります。
  4. パフォーマンス。ランタイムは、メソッド呼び出しのたびにif result is a promise then awaitチェックを挿入する必要があります。
2
CodesInChaos

すべての関数を待ちたくない場合があるため。一部の関数を同期的に実行する場合があります。

あなたの例は「危険なほど間違っている」のではなく、単に同期しているだけです。

ちなみに、isAdmin()という名前の関数をawaitする必要はありません。とにかくほぼすぐに返されるはずです。また、ifステートメントは続行する前に戻り結果を必要とするため、非同期で実行されることすらありません。

1つではなく2つのキーワードが使用される理由については、 Async DunctionsのTypeScript提案 で説明されています。

非同期関数は、JavaScript関数、パラメーター化された矢印関数、メソッド、またはGet Accessorであり、接頭辞としてasync修飾子が付いています。この修飾子は、関数本体の転置が必要であり、キーワードawaitを識別子ではなく単項式として扱う必要があることをコンパイラーに通知します。

1
Robert Harvey