web-dev-qa-db-ja.com

ES8すぐに呼び出される非同期関数式

これらのコンストラクトが多く使用されるのを見たことはありませんが、通常、promiseを返さない関数でasync/awaitを利用するためにそれらを作成していることに気づきました。たとえば、

chan.consume(queue, (msg) => {
  this.pendingMsgs++; // executed immediately
  (async () => {
    await this.handleMessage(msg);
    this.pendingMsgs--;
    if (cancelled && this.pendingMsgs === 0) {
       await chan.close();
       await this.amqpConnectionPool.release(conn);
    } 
  })();
});

とは対照的に

chan.consume(queue, async (msg) => { // external lib does not expect a return value from this callback
  this.pendingMsgs++;  // executed in promise context(?)
  await this.handleMessage(msg);
  this.pendingMsgs--;
    if (cancelled && this.pendingMsgs === 0) {
       await chan.close();
       await this.amqpConnectionPool.release(conn);
    }
});

または

chan.consume(queue, (msg) => {
  this.pendingMsgs++;  // no await - excess function decls & nesting
  this.handleMessage(msg).then(() => {
    this.pendingMsgs--;
    if (cancelled && this.pendingMsgs === 0) {
       chan.close().then(() => {
         this.amqpConnectionPool.release(conn);
       });
    }
  });
});

これは「もの」ですか?ここに注意すべき落とし穴はありますか?このような状況での非同期/待機の使用についての内訳は何ですか?

17
Drew R

これは「もの」ですか?

はい。それは時々現れます、例えば。 ここ 。それらはIIAFEとして知られています:-)
矢印に焦点を当てたい場合は、IIAAFと呼ぶこともできます。

知っておくべき落とし穴はありますか?

Promise-returning関数を呼び出し、その結果を他の場所に返さない場合は、あなたが自分でpromiseの責任を負います。つまり、promiseからのエラーを処理する必要があります。したがって、パターンは一般的に次のようになります。

(async () => {
    …
})().catch(err => {
    console.error(err);
});

未処理の拒否イベントを気にしたくない場合。

このような状況でのasync/awaitの使用に関する内訳は?

thenバージョンと比較すると、それほど多くありません。ただし、「外部libはこのコールバックからの戻り値を期待していません」と言っているため、非同期コールバックとのライブラリの非互換性を示唆している可能性があります。何をしているのかまた、コールバックから同期的にスローされる例外に依存している可能性があるため、ライブラリがここで期待するものに依存します(予期しない場合は、将来変更されるかどうか)。ライブラリがプロミスの戻り値を特別に扱い始める場合に備えて、将来の非互換性を望まないでください。

ただし、読みやすさの点から、async関数を直接コールバックとして直接渡す2番目のパターンをお勧めします。ライブラリにpromiseを返さないようにする場合は、コールバックをラップするヘルパー関数を作成します。

function toVoid(fn) {
    return (...args) => void fn(...args);
}
function promiseToVoid(fn) {
    return (...args) => void fn(...args).catch(console.error);
}

これは次のように使用できます。

chan.consume(queue, toVoid(async (msg) => {
     … // use `await` freely
}));
34
Bergi