コールバックによる非同期並列動作

async ライブラリには、parallel という便利なメソッドがあり、実行する非同期関数のコレクションと、すべての関数が正常に完了した後に実行するオプションのコールバックを受け取ります。

ドキュメントによると、次のように動作します。

前の関数が完了するまで待たずに、関数のタスク コレクションを並列で実行します。いずれかの関数がコールバックにエラーを渡すと、エラーの値を使用してメイン コールバックが直ちに呼び出されます。タスクが完了すると、結果が配列として最終コールバックに渡されます。

ただし、一部のユースケースでコールバック関数が呼び出されるかどうかについては、非常に混乱する可能性があり、コールバック地獄のある大規模なレガシー コード ベースを読んでいるときにかなり混乱しました。コードと出力例については、以下を参照してください。

  • すべてのタスクは実行されますが、コールバックは実行されません
import async from 'async';

const task = {
  A: true,
  B: true,
};

async.parallel(
  [
    function (done) {
      if(task.A) {
        console.log('does A');
        return;
      }
      done(null);
    },
    function (done) {
      if(task.B) {
        console.log('does B');
        return;
      }
      done(null);
    },
  ],
  function (err) {
    if (err) {
      console.log(err);
      return;
    }
    console.log('does callback');
  },
);

/* console output
does A
does B
*/
  • 1つのタスクは実行されますが、コールバックは実行されません
import async from 'async';

const task = {
  A: true,
  B: false,
};

async.parallel(
  [
    function (done) {
      if(task.A) {
        console.log('does A');
        return;
      }
      done(null);
    },
    function (done) {
      if(task.B) {
        console.log('does B');
        return;
      }
      done(null);
    },
  ],
  function (err) {
    if (err) {
      console.log(err);
      return;
    }
    console.log('does callback');
  },
);

/* console output
does A
*/
  • タスクが実行されず、その後コールバックが実行される
import async from 'async';

const task = {
  A: false,
  B: false,
};

async.parallel(
  [
    function (done) {
      if(task.A) {
        console.log('does A');
        return;
      }
      done(null);
    },
    function (done) {
      if(task.B) {
        console.log('does B');
        return;
      }
      done(null);
    },
  ],
  function (err) {
    if (err) {
      console.log(err);
      return;
    }
    console.log('does callback');
  },
);

/* console output
does callback
*/
  • 1つのタスクがコールバックで実行される
import async from 'async';

const task = {
  A: true,
  B: false,
};

async.parallel(
  [
    function (done) {
      if(task.A) {
        setTimeout(() => {
          console.log('does A');
          done(null);
        }, 100);
        return;
      }
      done(null);
    },
    function (done) {
      if(task.B) {
        console.log('does B');
        return;
      }
      done(null);
    },
  ],
  function (err) {
    if (err) {
      console.log(err);
      return;
    }
    console.log('does callback');
  },
);

/* console output
does A
does callback
*/

ご覧のとおり、callback は、すべての並列関数から最終的に正常に呼び出された場合にのみ呼び出されます。エラーの場合については、ドキュメントに明確に記載されています。

いずれかの関数がコールバックにエラーを渡すと、エラーの値を使用してメイン コールバックが直ちに呼び出されます。

参考文献

nodejs javascript