34

await次の EcmaScript にasync 関数とキーワードを追加するという現在の議論について混乱しています。

asyncキーワードの前にキーワードが必要な理由がわかりませんfunction

私の観点からすると、キーワードはジェネレーターまたはプロミスの完了awaitを待つため、関数で十分なはずです。return

awaitasync追加のマーカーなしで、通常の関数とジェネレーター関数内で簡単に使用できる必要があります。

の結果として使用できる関数を作成する必要がある場合はawait、単にプロミスを使用します。

私の質問の理由は、次の例が由来するこの良い説明です。

async function setupNewUser(name) {  
  var invitations,
      newUser = await createUser(name),
      friends = await getFacebookFriends(name);

  if (friends) {
    invitations = await inviteFacebookFriends(friends);
  }

  // some more logic
}

関数の実行が、すべての await が満たされるまでホール関数の終了を待機する場合は、通常の関数として実行することもできます。

function setupNewUser(name) {  
  var invitations,
      newUser = await createUser(name),
      friends = await getFacebookFriends(name);

  if (friends) {
    invitations = await inviteFacebookFriends(friends);
  }

  // return because createUser() and getFacebookFriends() and maybe inviteFacebookFriends() finished their awaited result.

}

私の意見では、次のティック(フルフィルメントを待つ)が完了するまで、関数全体の実行が保持されます。Generator-Function との違いは、next() がオブジェクトの値と完了フィールドをトリガーして変更することです。代わりに、関数は完了時に結果を返すだけで、トリガーは while ループのような関数内部トリガーです。

4

4 に答える 4

19

関数を としてマークすることにより、asyncJS に常に Promise を返すように指示します。

常にPromise を返すため、独自のブロック内でPromiseを待機することもできます。1 つの巨大な Promise チェーンのように想像してみてください。関数の内部で発生したことは、内部.then()ブロックに効果的にボルトで固定され、返されるの.then()はチェーンの最終的なものです。

例えばこんな機能…

async function test() {
  return 'hello world';
}

... Promise を返します。.then()そのため、1 つのようにすべてを実行できます。

test().then(message => {
  // message = 'hello world'
});

そう...

async function test() {
  const user = await getUser();
  const report = await user.getReport();
  report.read = true
  return report;
}

にほぼ類似しています...

function test() {
  return getUser().then(function (user) {
    return user.getReport().then(function (report) {
      report.read = true;
      return report;
    });
  });
}

どちらの場合も、渡されたコールバックは最初のパラメータとしてtest().then()受け取ります。report

ジェネレーター (つまり、関数をマークしてキーワード*を使用するyield) は、まったく別の概念です。彼らは約束を使用しません。これらを使用すると、コードのさまざまな部分間を効果的に「ジャンプ」して、関数内から結果を生成し、そのポイントに戻って次のyieldブロックを再開できます。

それらはいくぶん似ていますが (つまり、別の場所で何かが発生するまで実行を「停止」する)、Promise 実行の内部順序を乱すasync/awaitため、そのような錯覚を与えるだけです。実際には待っているのではなく、コールバックが発生したときにシャッフルしているだけです。

対照的に、ジェネレーターは異なる方法で実装されているため、ジェネレーターは状態を維持して反復処理できます。繰り返しますが、Promises とは何の関係もありません。

この記事を書いている時点では、async/await のサポートは怖いので、この線はさらにあいまいです。Chakracore はネイティブでサポートしており、V8 では近日公開予定です。それまでの間、Babel のようなトランスパイラーを使用async/awaitすると、コードを作成してジェネレーターに変換できます。したがって、ジェネレーターと async/await が同じであると結論付けるのは誤りです。そうではありません... たまたま、yieldPromises と一緒に機能する方法をろくでなしにして、同様の結果を得ることができます。

更新: 2017 年 11 月

Node LTS がネイティブでasync/awaitサポートされるようになったため、ジェネレーターを使用して Promise をシミュレートする必要はありません。

于 2016-09-08T06:40:43.963 に答える
10

これらの回答はすべて、 async キーワードが優れている理由について有効な議論を提供していますが、仕様に追加する必要があった本当の理由について実際に言及しているものはありません。

その理由は、これがES7より前の有効なJSだったからです

function await(x) {
  return 'awaiting ' + x
}

function foo() {
  return(await(42))
}

あなたの論理によれば、またはをfoo()返しますPromise{42}"awaiting 42"?(Promise を返すと下位互換性が失われます)

答えは次のとおりawaitです。通常の識別子であり、非同期関数内のキーワードとしてのみ扱われるため、何らかの方法でマークする必要があります。

おもしろい事実: 元の仕様ではfunction^ foo() {}、非同期構文の軽量化が提案されていました。

于 2017-01-19T14:25:29.690 に答える
3

前に async キーワードを付けた理由は単純で、戻り値が promise に変換されることがわかります。キーワードがない場合、インタプリタはどのようにしてこれを行うことを知るでしょうか。これは C# で最初に導入されたもので、EcmaScript は TypeScript から多くのものを取り入れていると思います。TypeScript と C# は Anders Hejlsberg によって考案され、類似しています。関数があるとしましょう(これは非同期作業を行うためのものです)

 function timeoutPromise() {  
     return (new Promise(function(resolve, reject) {
         var random = Math.random()*1000;
         setTimeout(
             function() {
                 resolve(random);
             }, random);
     }));
 }

この関数は、ランダムな時間を待機させ、Promise (jQuery を使用する場合、Promise は Deferred に似ています) オブジェクトを返します。今日この関数を使用するには、次のように記述します。

function test(){
    timeoutPromise().then(function(waited){
        console.log('I waited' + waited);
    });
}

そして、これは問題ありません。ログメッセージを返してみましょう

function test(){
    return timeoutPromise().then(function(waited){
        var message = 'I waited' + waited;
        console.log(message);
        return message; //this is where jQuery Deferred is different then a Promise and better in my opinion
    });
}

これは悪くありませんが、コードには 2 つの return ステートメントと 1 つの関数があります。

非同期では、これは次のようになります

  async function test(){
      var message = 'I waited' +  (await timeoutPromise());
      console.log(message);
      return message;
  }

コードは短く、インラインです。大量の .then() または . done() コードがどれほど読めないかがわかります。

関数の前に async キーワードがあるのはなぜですか。これは、戻り値が返されるものではないことを示しています。理論的には、これを書くことができます (これは c# で実行できますが、まだ実行されていないため、js で許可されるかどうかはわかりません)。

 async function test(wait){
     if(wait == true){
         return await timeoutPromise();
     }
     return 5;                
 }

ご覧のとおり、数値を返しますが、実際の戻り値は Promise であり、使用する必要はありません return new Promise(function(resolve, reject) { resolve(5);}; 。数値を待機できないため、Promise のみがawait test(false)例外をスローしawait test(true)、前に async を指定しない場合は例外をスローしません。

于 2016-06-09T00:50:33.950 に答える