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


86

最初の関数には条件付きの戻りパラメーターがあり、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、具体的な詳細がないタイプエラーを受け取りました。

できないのはなぜあなたの関数のスコープの機能の外?私はそれが砂糖の約束であることを知っているので、それは連鎖しなければなりません、しかしなぜ私は別の約束を待つことができるのに、外では私はできないのですか?awaitasyncthencountPlayerawait isInLobby


あなたは私たちを見ることができますどこあなたがやったawait isInLobby()、そしてどのようにinLobby使用されていますか?また、どこで/どのようにcountPlayer呼ばれますか?
ベルギ2016

@Bergiリポジトリを実際のコンテキストにリンクしました。質問に入れるにはコードが多すぎます
Sterling Archer

問題がどこにあるのかわかりません(おそらくすでにリポジトリを更新しています)?そのisInLobby().then( … countPlayer().then …部分を参照する場合、解決策は簡単です。それらの呼び出しが含まれている関数((req, res) =>1つ)を作成するだけasyncです。
ベルギ2016

@Bergi問題はそれが壊れたということではなく、そのまま動作します。トップレベルの待機が問題にならない理由がわかりませんでした。モジュール全体を非同期関数としてスコープすることなく、まだ存在していないことが判明しました
Sterling Archer

しかし、コードにトップレベル はまったく必要ありませんawaitか?だから、質問の問題とはあまり関係のない答えを受け入れてくれたのではないかと思いました。
ベルギ2016

回答:


74

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

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

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

今、任意の輸入はというファイルdata.jsあなたのモジュールのロードのすべてが今ブロックされているので、完了をフェッチするまで実行されません。これは、同期的かつ予測可能に実行されるトップレベルのJavascriptに慣れているため、アプリモジュールの順序について推論することを非常に困難にします。これが許可されている場合、関数がいつ定義されるかを知るのは難しいことです。

私の見解では、モジュールをロードするだけで副作用が発生するのは悪い習慣です。つまり、モジュールの消費者は、モジュールを要求するだけで副作用が発生します。これにより、モジュールを使用できる場所が大幅に制限されます。トップレベルawaitとは、ロード時にAPIから読み取っている、またはサービスを呼び出していることを意味します代わりに、コンシューマーが自分のペースで使用できる非同期関数をエクスポートする必要があります。


それは良いリンクです、ありがとう。トップレベルのサポートがないのは残念です。そうだといいのですが。現在のところ、私はここに約束を入れ子にする必要がありますが、それは非常に悪い習慣であり、私はそれが好きではありません。:(ありがとう。
スターリングアーチャー

@SterlingArcherあるいは、非同期生命維持を使用する:void async function() { const inLobby = await isInLobby() }()
robertklep

@robertklepは、そのスコープinLobbyを関数に適用してアクセスできないようにしませんか?
スターリングアーチャー

@SterlingArcherはい、そうです。すべてのコードをそこに移動する必要があります(基本的には「トップレベル」にします)。これは、使用する代わりの方法です.then()(申し訳ありませんが、もう少し明確にする必要があります)。
robertklep 2016

同意しないでください。data.js自体とそのすべての依存関係をロードしている間、data.jsのユーザーは「ブロック」されますが、この「ブロック」の概念自体は悪くありません。トップレベルのawaitは、使用が「リリース」される前に必要と思われる依存関係をロードするものと見なすことができます。
イブラヒムベンサラ

129

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

(async () => {
    await ...

    // all of the script.... 

})();
// nothing else

これにより、awaitを使用できるasyncを使用したクイック機能が作成されます。それはあなたに素晴らしい非同期関数を作る必要性を節約します!//クレジットSilve2611


3
さらに詳しく説明し、これが機能する理由を説明してください。
ポールバック

12
この答えに反対票を投じることは非常に愚かです。それはあなたがawaitを使うことができる非同期で速い機能を作ります。それはあなたに素晴らしい非同期関数を作る必要性を節約します!
Silve2611 2017

55
awaitこの無名関数を使用する必要があるため、問題は解決しません。これも、関数の外部からは機能しません。
マイケル

では、これはエラー状態をどのように処理しますか?また、awaitコード内に到達しますか?
マヌエルヘルナンデス

TKSは、これは特別にコールバック約束に一度ストレージのgetItem取得するために完全に戻っREPONSEでログインAPI、フェッチ、greateの助けである
テスHSU

10

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

;(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 () => {...}'


20
間違っているのはリフォーマッターではありません。セミコロンがないと、実行時に関数が解析される方法であり、エラー、改行、または改行なしが発生します。あなたの例の正しい解決策はadd(1);、async関数の前ではなく後にセミコロンを追加することです。
マダラの幽霊

11
また、これが当面の質問とどのように関連しているかを正直に理解していません。
マダラの幽霊

はい、あなたが正しい。また、ランタイムにはセミコロンが必要です。
Viliam Simko 2018


1

typescript 3.8以降、トップレベルの待機を行うことができます
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#-top-level-await
投稿から:
これは、以前はJavaScript(および同様の機能を持つ他のほとんどの言語)では、awaitは非同期関数の本体内でのみ許可されていました。ただし、トップレベルのawaitを使用すると、モジュールのトップレベルでawaitを使用できます。

const response = await fetch("...");
const greeting = await response.text();
console.log(greeting);

// Make sure we're a module
export {};

微妙な点があることに注意してください。トップレベルの待機はモジュールのトップレベルでのみ機能し、TypeScriptがインポートまたはエクスポートを検出した場合にのみファイルはモジュールと見なされます。基本的なケースでは、これを確認するために、エクスポート{}を定型文として書き出す必要がある場合があります。

トップレベルの待機は、現時点で期待できるすべての環境で機能するとは限りません。現在、トップレベルの待機を使用できるのは、ターゲットコンパイラオプションがes2017以上で、モジュールがesnextまたはsystemの場合のみです。複数の環境およびバンドラー内でのサポートは制限されている場合や、実験的なサポートを有効にする必要がある場合があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.