awaitは非同期関数でのみ有効です


129

私はこのコードを書いた lib/helper.js

var myfunction = async function(x,y) {
   ....
   reutrn [variableA, variableB]
}
exports.myfunction = myfunction;

それから私はそれを別のファイルで使用しようとしました

 var helper = require('./helper.js');   
 var start = function(a,b){
     ....
     const result = await helper.myfunction('test','test');
 }
 exports.start = start;

エラーが発生しました

「待機は非同期関数でのみ有効です」

どうした?


1
さて、問題は関数await内でのみ使用できることasyncです。つまりawait、関数を非同期にするため、そのように宣言する必要があります。
2018年

現在のエラーは何ですか?
acdcjunior 2018年

それでも同じ、SyntaxError:awaitは非同期関数でのみ有効です
j.doe

コードについてより多くのコンテキストを共有する必要があります。
Ele

回答:


158

エラーはに関するものではなく、に関するmyfunctionものstartです。

async function start() {
   ....

   const result = await helper.myfunction('test', 'test');
}

// My function
const myfunction = async function(x, y) {
  return [
    x,
    y,
  ];
}

// Start function
const start = async function(a, b) {
  const result = await myfunction('test', 'test');
  
  console.log(result);
}

// Call start
start();



私が使用して、既知のアンチパターンについてあなたにアドバイスするために、この質問の機会を利用await:ありますreturn await


違う

async function myfunction() {
  console.log('Inside of myfunction');
}

// Here we wait for the myfunction to finish
// and then returns a promise that'll be waited for aswell
// It's useless to wait the myfunction to finish before to return
// we can simply returns a promise that will be resolved later

// useless async here
async function start() {
  // useless await here
  return await myfunction();
}

// Call start
(async() => {
  console.log('before start');

  await start();
  
  console.log('after start');
})();


正しい

async function myfunction() {
  console.log('Inside of myfunction');
}

// Here we wait for the myfunction to finish
// and then returns a promise that'll be waited for aswell
// It's useless to wait the myfunction to finish before to return
// we can simply returns a promise that will be resolved later

// Also point that we don't use async keyword on the function because
// we can simply returns the promise returned by myfunction
function start() {
  return myfunction();
}

// Call start
(async() => {
  console.log('before start');

  await start();
  
  console.log('after start');
})();


また、return await正しく重要な特別なケースがあることを知ってください:(try / catchを使用)

「返品待ち」でパフォーマンスの問題はありますか?


しかし、これは機能していません。コードを更新しました。それでも同じエラーが発生する
j.doe 2018年

@ j.doe私はスニペットを追加しました
GrégoryのNEUTを

2
ありがとう、問題が見つかりました。start()関数がコールバック内で実行しようとしていました。解決策は:const start = async function(a、b){task.get(options、async function(error、result1){const result = await myfunction( 'test'、 'test');
j.doe

そのノードがシングルスレッドであることを考慮してください。1分あたりのリクエストを減らし、フルフィルリクエスト間の遅延も増やします。
Rishabh Dhiman

1
「正しい」の例ではstartasync関数として宣言する必要がないことは言及する価値があります(より明示的にするために、とにかくそうすることを選択する人もいます)
Gershom

11

このエラーが発生したとき、「async」関数内でmap関数が呼び出されたことが判明したため、このエラーメッセージは実際には「async」としてマークされていないmap関数を参照していました。この問題を回避するには、map関数から "await"呼び出しを取り、期待される動作を得る別の方法を考え出しました。

var myfunction = async function(x,y) {
    ....
    someArray.map(someVariable => { // <- This was the function giving the error
        return await someFunction(someVariable);
    });
}

2
これは私にとって問題でした。map関数をforループに置き換えました。これは私にとって簡単な解決策でした。ただし、このソリューションは、コードによっては機能しない場合があります。
トーマス

6
FYIあなたもできるsomeArray.map(async (someVariable) => { return await someFunction(someVariable)})
ptim

1
awaitので、あなたのコードでは、誤解を招くされるArray.map非同期関数としての機能を処理しません。完全に明確にするために、map関数が終了した後、someFunctionすべてが保留になります。関数が終了するのを本当に待ちたい場合は、:await Promise.all(someArray.map(someVariable => someFunction(someVariable)))またはawait Promise.all(someArray.map(someFunction)))
GrégoryのNEUT

9

を使用するにはawait、その実行コンテキストがasync自然である必要があります

それが言ったように、あなたは何よりも先にタスクにexecuting context進んで進んでいるあなたの性質を定義する必要がありますawait

ただ、置くasync前にfn、あなたのここで宣言asyncタスクが実行されます。

var start = async function(a, b) { 
  // Your async task will execute with await
  await foo()
  console.log('I will execute after foo get either resolved/rejected')
}

説明:

あなたの質問では、あなたは本質的にあり、並行して実行されるをインポートしてmethodいますasynchronous。しかし、そのasyncメソッドを実行しようとしている場所は、使用execution contextするために定義asyncする必要がある別の内部にありますawait

 var helper = require('./helper.js');   
 var start = async function(a,b){
     ....
     const result = await helper.myfunction('test','test');
 }
 exports.start = start;

フードの下で何が起こっているのだろうか

awaitpromise / future / task-returningメソッド/関数asyncを使用し、awaitを使用できるようにメソッド/関数をマークします。

また、に精通しているpromises場合awaitは、実際に同じプロセスで約束/解決を行っています。promiseのチェーンを作成し、resolveコールバックで次のタスクを実行します。

詳細については、MDN DOCSを参照してください。


start関数にasyncがあっても、エラーが発生します
j.doe

どこに行方不明になっていてこのエラーが出ているのかわかりません。このエラーを解決するための複雑な説明はありません。
Satyam Pathak

これは適切な答えであり、実際に下線の理由を説明しました。賛成票を投じた。
linehrr '10 / 10/19

3

現在の実装では、async/ awaitのみサポートawaitのキーワード内部async機能は、あなたの変更startに使用できるように、関数のシグネチャをawait内側にstart

 var start = async function(a, b) {

 }

興味のある方のために、トップレベルの提案awaitは現在ステージ2にあります:https : //github.com/tc39/proposal-top-level-await


1
残念ながら、これが基本的に意味することは、コードベース全体ですべての関数を非同期にする必要があるということです。awaitを使用する場合は、非同期関数で行う必要があります。つまり、awaitを呼び出す関数でその関数の応答を待つ必要があります。これも、すべての関数が非同期になる必要があることを意味します。これは、await asyncを使用する準備ができていないことを意味します。awaitを使用して非同期メソッドを呼び出すことができる場合は、現在の関数が同期か非同期かに関係なく、プライムタイムの準備ができています。
Rodney P. Barbati

1
外部プロセスの結果に依存する間接性の任意のレベルを通過するすべての関数は、で定義する必要があり、それで定義する必要がありますasync-それがの全体のポイントですasync
Gershom

現在、--experimental-repl-awaitオプションを使用してノード複製で使用できます。
ウッチ

3

私は同じ問題を抱えていて、次のコードブロックが同じエラーメッセージを出していました:

repositories.forEach( repo => {
        const commits = await getCommits(repo);
        displayCommit(commits);
});

問題は、メソッドgetCommits()が非同期でしたが、Promiseによって生成された引数repoを渡していたことです。そのため、async(repo)のようにasyncという単語を追加する必要があり、それが機能し始めました。

repositories.forEach( async(repo) => {
        const commits = await getCommits(repo);
        displayCommit(commits);
});

0

async / awaitはpromiseを処理するメカニズムであり、2つの方法で実行できます

functionWhichReturnsPromise()
            .then(result => {
                console.log(result);
            })
            .cathc(err => {
                console.log(result);

            });

または、awaitを使用して、最初に完全に提出するという約束を待つことができます。つまり、拒否または解決されます。

関数内でawait(フルフィルメントのプロミスの待機)を使用したい場合、非同期でプロフィルされるのプロミスを待機しているため、コンテナー関数は非同期関数でなければなりません|| 理にかなっていますか?

async function getRecipesAw(){
            const IDs = await getIds; // returns promise
            const recipe = await getRecipe(IDs[2]); // returns promise
            return recipe; // returning a promise
        }

        getRecipesAw().then(result=>{
            console.log(result);
        }).catch(error=>{
            console.log(error);
        });

-2

「待機は非同期関数でのみ有効です」

しかし、なぜ?'await'は非同期呼び出しを明示的に同期呼び出しに変換するため、呼び出し元は非同期(または非同期)にすることができません。少なくとも、 'await'で行われた呼び出しのためではありません。


1
実際、awaitは結果を待つのではなく、すぐにpromiseを返します。これはまさに私が伝えようとしていたことです。awaitが実際に待機し、呼び出し元に制御を返さなかった場合、awaitキーワードを含む関数は文字通り非同期とマークできません。しかし、その代わりに、awaitを含む関数、またはawaitを含む関数を最終的に呼び出す関数を呼び出す関数は非同期である必要があります。基本的に、awaitを1回でも呼び出す場合、すべての関数を非同期としてマークする必要があります。
Rodney P. Barbati

-5

はい、await / asyncは素晴らしいコンセプトでしたが、実装は完全に壊れています。

何らかの理由で、awaitキーワードは、非同期メソッド内でのみ使用できるように実装されています。これは実際にはバグですが、ここではそのように呼ばれることはありません。このバグの修正は、呼び出し関数自体が同期か非同期かに関係なく、非同期関数を呼び出すためにのみ使用できるようにawaitキーワードを実装することです。

このバグのため、awaitを使用してコードのどこかで実際の非同期関数を呼び出す場合、すべての関数を非同期としてマークし、すべての関数呼び出しでawaitを使用する必要があります。

これは本質的に、アプリケーション全体のすべての関数にpromiseのオーバーヘッドを追加する必要があることを意味します。そのほとんどは非同期ではなく、非同期になることもありません。

実際に考えてみると、関数でawaitを使用するには、awaitキーワードを含む関数が非同期になる必要があります。これは、awaitキーワードが、awaitキーワードが見つかった関数で処理を一時停止するためです。その関数での処理が一時停止している場合は、非同期ではありません。

それで、javascriptとECMAScriptの開発者に-次のようにawait / async実装を修正してください...

  • awaitは非同期関数の呼び出しにのみ使用できます。
  • awaitは、同期または非同期のあらゆる種類の関数で使用できます。
  • エラーメッセージを「awaitは非同期関数でのみ有効」から「awaitは非同期関数の呼び出しにのみ使用できます」に変更します。

必要に応じてバグと呼んでもかまいませんが、私は同意しません。「一時停止」するコードなどはありません-むしろ、何らかの外部プロセス(通常はio)の結果なしでは完了できないコードがあります。シングルスレッドのjavascript VMとは対照的に、多くの外部プロセスが同時に(非同期で)実行できるため、このようなコードは「非同期」と呼ばれます。多くの関数をリファクタリングする必要がある場合asyncは、関数の多くが外部プロセスの結果を必要とするという事実を反映しています。それは私の意見では完全に標準的です。
Gershom

await関数呼び出しでのみ使用できるように制限するというひどい欠点にも言及する価値があります。単一の外部プロセスの場合、そのプロセスが完了すると、JavaScriptコードの単一のポイントのみが通知されます。たとえば、3つの独立した目的でファイルのコンテンツが必要な場合、それぞれの目的で独立して行う必要があります。let content = await readTheFile();これは、「ファイルのコンテンツの約束」を待つことができないためです。読んだ"。
Gershom

さて、一時停止するコードや完了できないコードではなく、ブロックされた待機についてはどうでしょうか。ここに問題があります-待機がブロックされている関数または完了できない関数は、awaitキーワードを含む関数です。awaitキーワードで呼び出されているのは非同期関数ではありません。したがって、awaitキーワードを含む関数は、必ず非同期としてマークする必要はありません。非同期の逆である、待機ブロックされます。
Rodney P. Barbati

これを完全に明確にするために、次の点を考慮してください。awaitは、非同期関数を同期しているように見せることで非同期関数の使用を簡略化することを目的としています(つまり、特定の順序で処理を実行できます)。awaitを含む関数を強制的に非同期にすることは完全に誤った呼び名です。awaitを使用して同期するようにしました。待機を含む関数は、考えられるあらゆる方法で、非同期関数ではありません!!!
Rodney P. Barbati

1
@Gershom-それは合理的に聞こえます。ありがとう!
Rodney P. Barbati
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.