web-dev-qa-db-ja.com

async / awaitとpromiseの違いは?

私のnodeJSアプリで何を使用するかについての回答を探しています。

Mssqlへの一般的なdBアクセスを処理するコードがあります。このコードはasync関数を使用して記述されており、その後、Promiseを使用してその関数を呼び出すと、すべて正常に動作します。

アプリが大きくなり、コードが大きくなるので、ロジックの一部を関数に移動してから呼び出すことを計画しています。

だから私の質問は:async/awaitとpromiseの組み合わせを使用することには欠点がありますか、それとも本当に問題ありませんか?

Async/awaitを使用すると、何かを返す前に複数のdbを読み書きする必要があり、これらのいくつかの結果が必要になるため、より読みやすいコードを簡単に記述できます。

だから問題はより良いアプローチは何ですか?設定済みで変更できないdBレイヤーで非同期/待機ロジックレイヤーを非同期/待機すると、関数呼び出しを非同期/待機できます。または、ロジックのプロミスを実行すると、関数呼び出しのプロミスで立ち往生します。

したがって、よりクリーンなコードを記述できることに加えて、一方が他方よりも多くの利点を持っている場合は、誰かが私にもっと洞察を与えることを望みます。

9
MisterniceGuy

_async/await_とpromiseは密接に関連しています。 async関数はpromiseを返し、awaitはpromiseが解決されるのを待つための構文糖衣です。

Promiseとasync関数を混在させることによる唯一の欠点は、コードの可読性と保守性ですが、非同期関数の戻り値をpromiseとして、また通常のawaitとして確実に使用できます。 promiseを返す関数。

どちらを選択するかは、ほとんどの場合、可用性(node.js /ブラウザーがasyncをサポートしているか)と美的設定に依存しますが、大まかな経験則(当時の自分の設定に基づく)書き込み)は:

非同期コードを連続して実行する必要がある場合:_async/await_の使用を検討してください:

_return asyncFunction()
.then(result => f1(result))
.then(result2 => f2(result2));
_

_const result = await asyncFunction();
const result2 = await f1(result);
return await f2(result2);
_

ネストされたpromiseが必要な場合:_async/await_を使用します。

_return asyncFunction()
.then(result => {
  return f1(result)
  .then(result2 => f2(result, result2);
})
_

_const result = await asyncFunction();
const result2 = await f1(result);
return await f2(result, result2);
_

並行して実行する必要がある場合は、promiseを使用してください。

_return Promise.all(arrayOfIDs.map(id => asyncFn(id)))
_

式内でawaitを使用して、次のような複数のタスクを待機できることが示唆されています。
*注、これはまだ左から右に順番に待機しているため、エラーが予想されない場合は問題ありません。それ以外の場合、Promise.all()fail fast behaviour のために動作が異なります

_const [r1, r2, r3] = [await task1, await task2, await task3];
_
_(async function() {
  function t1(t) {
    console.time(`task ${t}`);
    console.log(`start task ${t}`);
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        console.timeEnd(`task ${t}`);
        resolve();
      }, t);
    })
  }

  console.log('Create Promises');
  const task1 = t1(100);
  const task2 = t1(200);
  const task3 = t1(10);

  console.log('Await for each task');
  const [r1, r2, r3] = [await task1, await task2, await task3];

  console.log('Done');
}())_

ただし、_Promise.all_と同様に、エラーが発生した場合は並列プロミスを適切に処理する必要があります。詳しくは こちら をご覧ください。

前のコードを次のコードと混同しないように注意してください。

_let [r1, r2] = [await t1(100), await t2(200)];
_
_function t1(t) {
  console.time(`task ${t}`);
  console.log(`start task ${t}`);
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.timeEnd(`task ${t}`);
      resolve();
    }, t);
  })
}
console.log('Promise');
Promise.all([t1(100), t1(200), t1(10)]).then(async() => {

  console.log('Await');
  let [r1, r2, r3] = [await t1(100), await t1(200), await t1(10)]
});_

これら2つの方法を使用することは同等ではありません。 違いについてもっと読む

結局のところ、_Promise.all_は、任意の数のタスクに適切に対応できる、よりクリーンなアプローチです。

9
lucascaro

この時点で、Promiseを使用する唯一の理由は、Promise.all()を使用して複数の非同期ジョブを呼び出すことです。それ以外の場合、通常はasync/awaitまたはObservablesの方が適しています。

2
XaxD

実際にはノードのバージョンによって異なりますが、async/awaitを使用できる場合は、コードが読みやすくなり、保守しやすくなります。関数を「非同期」として定義すると、ネイティブのPromiseが返され、awaitを使用して呼び出すと、Promise.thenが実行されます。

注:待機呼び出しをtry/catch内に配置します。これは、Promiseが失敗した場合、catchブロック内で処理できる'catch'が発行されるためです。

try{
let res1 = await your-async-function(parameters);
let res2 = await your-promise-function(parameters);
await your-async-or-promise-function(parameters);
}
catch(ex){
// your error handler goes here
// error is caused by any of your called functions which fails its promise
// this methods breaks your call chain
}

また、次のように「キャッチ」を処理できます。

let result = await your-asyncFunction(parameters).catch((error)=>{//your error handler goes here});

このメソッドは例外を生成しないため、実行が続行されます。

ネイティブのPromiseモジュールの実装以外、async/awaitの間にパフォーマンスの違いはないと思います。

Nodeに組み込まれたネイティブのpromiseの代わりにbluebirdモジュールを使用することをお勧めします。

1

それはあなたがどのアプローチに適しているかに応じて、promiseとasync/awaitの両方が良いですが、非同期コードを記述したい場合は、同期コード構造を使用してasync/awaitアプローチを使用する必要があります。約束または非同期/待機スタイル。 Promiseを使用する場合:

function getFirstUser() {
    return getUsers().then(function(users) {
        return users[0].name;
    }).catch(function(err) {
        return {
          name: 'default user'
        };
    });
}

aysnc/awaitを使用する場合

async function getFirstUser() {
    try {
        let users = await getUsers();
        return users[0].name;
    } catch (err) {
        return {
            name: 'default user'
        };
    }
}

ここで、promiseアプローチでは、従うべき処理可能な構造が必要であり、async/awaitアプローチでは、「await」を使用して非同期関数の実行を保持します。

より明確にするためにこのリンクをチェックアウトできます訪問 https://medium.com/@bluepnume/learn-about-promises-before-you-start-using-async-await-eb148164a9c8

0
Sumit Kumar

昨日、Promiseチェーンの以前の値にアクセスするのが難しいため、nodejsとは関係なく、Promiseの使用からAsync/Awaitの使用に切り替えるという暫定的な決定をしました。 'bind'を使用して 'then'関数内の値を保存するコンパクトなソリューションを思いつきましたが、ローカル変数と引数への直接アクセスを可能にする点で、Asyncの方がはるかに優れていました(そうでした)。そして、Async/Awaitのより明白な利点は、もちろん、通常の関数呼び出しによく似た線形表記を優先して、煩わしい明示的な 'then'関数を排除することです。

しかし、今日の私の読書では、Async/Awaitに関する問題が明らかになりました。数年後のAsync/Awaitが修正されるまで、Promise(おそらくマクロプリプロセッサを使用して「then」関数をよりシンプルに見えるようにする)に固執すると思います。

ここに私が見つけた問題があります。私は間違っていること、簡単な解決策があることを知りたいです。

  1. 外側のtry/catchまたは最後のPromise.catch()が必要です。それ以外の場合、エラーと例外は失われます。

  2. 最終的な待機には、Promise.then()または追加の外部非同期関数のいずれかが必要です。

  3. 反復は、for/ofでのみ正しく実行でき、他の反復子では実行できません。

  4. Awaitは、一度に1つのPromiseのみを待機できます。Promise.allを使用したPromiseチェーンのような並行Promiseは待機できません。

  5. Awaitは、必要な場合にPromise.race()をサポートしていません。

0
David Spector