web-dev-qa-db-ja.com

プロミスを使用してトリガーされたイベントを待つ

次のコードでは、thingは私が制御しない外部オブジェクトです。 thingのイベントシステムの動作を変更することはできません。 fnが呼び出されると、エグゼキューターがイベントをリッスンし、最終的にそのイベントがトリガーされる一連の関数の待機を開始するpromiseを返します。

function fn() {

  return new Promise(async function(resolve, reject) {

      // This handler must be attached before `c` is called
      thing.once('myEvent', function(e) {
        resolve(e.data); // done
      });

      // The order of these functions calls is important,
      // and they may produce errors that need to be handled.
      await a();
      await b();
      await c(); // this causes myEvent

  });

}

これは正常に機能しますが、 私は聞いたことがあります これは約束のアンチパターンであり、fnasync関数にする必要があることを示しています。どうすればいいですか? fnasync関数にした場合、イベントハンドラー内からe.dataを解決するにはどうすればよいですか?

編集:

アンチパターンを説明し、このシナリオにどのように適用するかを説明するのに役立つので、私はBergiの回答を受け入れました。そうは言っても、上記のコードの方が読みやすく、何が起こっているのかを明示的に示しているので、そのままにしておきます。これは、ベストプラクティスを非難する初心者ではありません。それは、私のユースケースのためだけのものです。ルールに従うと、必要以上に複雑になります。もちろん、これによって特定の problems を受け入れることができますが、これを行うためのより良い方法が見つかるまで、それを受け入れなければなりません。

17
user993683

awaitコンストラクター内でPromiseingを実行しないでください-非同期コールバックの約束をそこで行うだけです。

async function fn() {
  await a();
  await b();
  await c(); // this causes myEvent
  return new Promise(function(resolve, reject) {
    thing.once('myEvent', function(e) {
      resolve(e.data); // done
    });
  });
}

最終的にイベントを発生させるプロセスを開始するものは、通常Promiseエグゼキューターコールバック内でも呼び出されますが(同期例外をキャッチするため)、通常はc関数が行います。

多分これは意図をよりよく表現します:

async function fn() {
  await a();
  await b();
  const {data} = await new Promise(resolve => {
    thing.once('myEvent', resolve);
    thing.c(); // this causes myEvent
  });
  return data;
}

もちろん、これは、他のイベントを呼び出したときに、イベントのリスニングを開始するだけでよいことを前提としています。その前にイベントが発生すると予想される場合は、基本的に並列実行との競合があります。その場合はPromise.allを使用することをお勧めします。

async function fn() {
  await a();
  await b();
  const [{data}, cResult] = await Promise.all([
    new Promise(resolve => thing.once('myEvent', resolve)),
    c()
  ]);
  return data;
}

ノードv11.13.0以降がある場合は、 events.once method を使用して、自分でプロミスを構築する必要がなく、エラーイベントも正しく処理します。

import { once } from 'events';

async function fn () {
  await a()
  await b()
  await c()
  await once(thing, 'myEvent')
}
23
Bergi