web-dev-qa-db-ja.com

非同期関数の外でawaitを使用する

最初のモジュールには条件付きの戻りパラメーターがあり、2番目のモジュールを実行または終了させるため、2つの非同期関数を連結しようとしました。ただし、仕様では見られない奇妙な動作を発見しました。

async function isInLobby() {
    //promise.all([chained methods here])
    let exit = false;
    if (someCondition) exit = true;
}

これは私のコードの卑劣なスニペットです(完全なスコープ ここ を見ることができます)。すでにロビーにいるプレイヤーがいるかどうかを単純にチェックしますが、それは無関係です。

次に、この非同期関数があります。

async function countPlayer() {
    const keyLength = await scardAsync(game);
    return keyLength;
}

exit === trueの場合、この関数を実行する必要はありません。

やってみた

const inLobby = await isInLobby();

これは結果を待つことを望んでいたので、inLobbyを使用してcountPlayerを条件付きで実行できますが、特定の詳細なしでtypeerrorを受け取りました。

await関数のスコープ外でasync関数を使用できないのはなぜですか?私はそれが砂糖の約束であることを知っているので、thenにチェーンする必要がありますが、なぜcountPlayerでは別の約束を待つことができますが、外ではawaitisInLobbyはできませんか?

50
Sterling Archer

トップレベルawaitはサポートされていません。 このGithubの問題 のように、これがなぜなのかについて、標準化委員会による議論がいくつかあります。

Githubの考え方 トップレベルの待機が悪い考えである理由についてもあります。具体的には、次のようなコードがある場合は次のように提案します。

// data.js
const data = await fetch( '/data.json' );
export default data;

これで、anydata.jsをインポートするファイルは、フェッチが完了するまで実行されないため、すべてのモジュールのロードがブロックされます。これは、トップレベルのJavaScriptを同期的かつ予測可能に実行するために使用されているため、アプリモジュールの順序について推論することを非常に困難にします。これが許可された場合、関数がいつ定義されるかを知るのは難しくなります。

私のパースペクティブは、モジュールをロードするだけで副作用があるのは悪い習慣だということです。つまり、モジュールを要求するだけで、モジュールの消費者は副作用を被ることになります。これにより、モジュールを使用できる場所が大きく制限されます。最上位のawaitは、おそらく、ロード時にAPIから読み込んでいるか、サービスを呼び出していることを意味します。代わりに、非同期でエクスポートする必要があります消費者が自分のペースで使用できる機能。

50
Andy Ray

もちろん、これは常にあります:

(async () => {
    await ...
})();

これにより、awaitを使用できるasyncのクイック機能が作成されます。これにより、非同期関数を作成する必要がなくなります。 //クレジットSilve2611

72

さらに良いのは、コードブロックの前にセミコロンを追加することです

;(async () => {
    await ...
})();

これにより、最初の括弧が前の行の末尾に移動する自動フォーマッター(vscodeなど)が防止されます。

この問題は、次の例で実証できます。

const add = x => y => x+y
const increment = add(1)
(async () => {
    await ...
})();

セミコロンなしでは、これは次のように再フォーマットされます。

const add = x => y => x+y
const increment = add(1)(async () => {
  await Promise(1)
})()

これは明らかに間違っています。非同期関数をyパラメーターとして割り当て、結果から関数を呼び出そうとするためです(実際には奇妙な文字列'1async () => {...}'

3
Viliam Simko