ESLintのルール「no-async-promise-executor」徹底解説!コードの読みやすさと保守性を向上させる

2024-04-06

ESLintのルール「no-async-promise-executor」解説

ESLintのルール「no-async-promise-executor」は、async 関数を Promise コンストラクタのexecutor関数として使用することを禁止します。このルールは、コードの読みやすさと保守性を向上させるために役立ちます。

問題点

async 関数を executor 関数として使用すると、以下の問題が発生する可能性があります。

  • コードの読みづらさ: async 関数は非同期処理を表すため、executor 関数内で使用すると、コードの意味が分かりにくくなります。
  • バグの発生: async 関数内で resolvereject を呼び出すと、意図せず非同期処理が開始される可能性があり、バグの原因となります。

解決策

async 関数を executor 関数として使用したい場合は、代わりに以下の方法を使用できます。

  • 通常の関数を使用する: async 関数を使用せず、通常の関数を executor 関数として使用します。
  • Promise.all を使用する: 複数の非同期処理を順番に実行したい場合は、Promise.all を使用できます。

NG例:

const promise = new Promise((resolve, reject) => {
  async function executor() {
    // 非同期処理
    const result = await someAsyncFunction();
    resolve(result);
  }

  executor();
});

OK例:

const promise = new Promise((resolve, reject) => {
  function executor() {
    // 非同期処理
    someAsyncFunction().then(result => {
      resolve(result);
    }).catch(error => {
      reject(error);
    });
  }

  executor();
});

設定方法

このルールを有効にするには、ESLintの設定ファイル(.eslintrc.json)に以下の設定を追加します。

{
  "rules": {
    "no-async-promise-executor": "error"
  }
}


ESLint no-async-promise-executor サンプルコード

NG 例

const promise = new Promise((resolve, reject) => {
  async function executor() {
    // 非同期処理
    const result = await someAsyncFunction();

    // 複数回の resolve 呼び出しはエラーになる
    resolve(result);
    resolve('This should not be called.');

    // 複数回の reject 呼び出しはエラーになる
    reject(new Error('Something went wrong.'));
    reject(new Error('This should not be called.'));
  }

  executor();
});

resolve / reject 呼び出しのタイミング

const promise = new Promise((resolve, reject) => {
  async function executor() {
    // 非同期処理開始前に resolve / reject を呼び出すと、
    // 処理が実行されない
    resolve('This should not be called.');
    reject(new Error('This should not be called.'));

    // 非同期処理
    const result = await someAsyncFunction();
    resolve(result);
  }

  executor();
});

try-catch の使用

const promise = new Promise((resolve, reject) => {
  async function executor() {
    try {
      // 非同期処理
      const result = await someAsyncFunction();
      resolve(result);
    } catch (error) {
      reject(error);
    }
  }

  executor();
});

async / await の混在

const promise = new Promise((resolve, reject) => {
  async function executor() {
    // 非同期処理
    const result = await someAsyncFunction();

    // async / await の混在はエラーになる
    resolve(result.then(() => {
      return 'This should not be called.';
    }));
  }

  executor();
});

Promise.all の使用

const promise = new Promise((resolve, reject) => {
  async function executor() {
    // Promise.all を使用したい場合は、
    // async 関数を executor 関数として使用しない
    const results = await Promise.all([
      someAsyncFunction1(),
      someAsyncFunction2(),
    ]);

    resolve(results);
  }

  executor();
});

OK 例

通常の関数を使用

const promise = new Promise((resolve, reject) => {
  function executor() {
    // 非同期処理
    someAsyncFunction().then(result => {
      resolve(result);
    }).catch(error => {
      reject(error);
    });
  }

  executor();
});

arrow function を使用

const promise = new Promise((resolve, reject) => {
  const executor = async () => {
    // 非同期処理
    const result = await someAsyncFunction();
    resolve(result);
  };

  executor();
});

Promise.all を使用

const promise = Promise.all([
  someAsyncFunction1(),
  someAsyncFunction2(),
]);

async 関数内で resolve / reject を直接呼び出す

const someFunction = async () => {
  // 非同期処理
  const result = await someAsyncFunction();

  // Promise を返す
  return new Promise((resolve, reject) => {
    resolve(result);
  });
};

const promise = someFunction();


ESLint no-async-promise-executor 違反を回避する方法

通常の関数を使用する

async 関数を使用せず、通常の関数を executor 関数として使用します。

const promise = new Promise((resolve, reject) => {
  function executor() {
    // 非同期処理
    someAsyncFunction().then(result => {
      resolve(result);
    }).catch(error => {
      reject(error);
    });
  }

  executor();
});

arrow function を使用

ES6 の arrow function を使用して、executor 関数を簡潔に記述できます。

const promise = new Promise((resolve, reject) => {
  const executor = async () => {
    // 非同期処理
    const result = await someAsyncFunction();
    resolve(result);
  };

  executor();
});

Promise.all を使用

複数の非同期処理を順番に実行したい場合は、Promise.all を使用できます。

const promise = Promise.all([
  someAsyncFunction1(),
  someAsyncFunction2(),
]);

async 関数内で resolve / reject を直接呼び出すことで、Promise を返すことができます。

const someFunction = async () => {
  // 非同期処理
  const result = await someAsyncFunction();

  // Promise を返す
  return new Promise((resolve, reject) => {
    resolve(result);
  });
};

const promise = someFunction();

その他のライブラリを使用する

bluebird などのライブラリには、Promise.promisify などの便利な関数があり、async 関数を Promise に変換することができます。

const promise = Promise.promisify(someAsyncFunction)();



ESLint ルール "no-object-constructor" の徹底解説: オブジェクトリテラル記法でコードをスッキリさせよう

no-object-constructor は、new キーワードなしで Object コンストラクタを使用することを禁止する ESLint ルールです。これは、オブジェクトリテラル記法の方が簡潔で読みやすいコードになるためです。ルール設定



JavaScriptのfinallyブロック:安全な使い方とno-unsafe-finallyルールの活用

概要ルール名: no-unsafe-finallyデフォルト設定: error使用可能なオプション: なし問題点finally ブロックは、try ブロック内で発生した例外に関わらず、必ず実行されます。そのため、finally ブロック内で例外が発生しても、それが隠蔽されてしまい、プログラムの動作がおかしくなる可能性があります。


JavaScript 開発者のための安全なコーディング:no-unsafe-negation ルール徹底解説

否定演算子は、式の結果を逆転させるために使用されます。例えば、以下のコードは x が 0 ではないことをチェックします。しかし、このコードは以下のように書き換えることもできます。一見同じように見えますが、2番目のコードは誤解を招きやすく、バグを引き起こす可能性があります。これは、=== 演算子が == 演算子とは異なる動作をするからです。


ESLint no-empty ルール:空のブロックを検知してコードの品質向上をサポート

空の if ステートメント: 条件文が常に false と評価される if ステートメント空の else ステートメント: 常に実行されない else ステートメント空の try / catch / finally ブロック: 何もしない try / catch / finally ブロック


ラベル変数はもう古い?ESLintの「no-label-var」ルールでモダンなコードへ

ESLint のルール "no-label-var" は、var キーワードを使ってラベル変数を宣言することを禁止します。これは、ラベル変数はほとんどの場合不要であり、コードの可読性を低下させる可能性があるためです。問題点var キーワードを使ってラベル変数を宣言すると、以下の問題が発生します。



ESLint no-empty ルール:空のブロックを検知してコードの品質向上をサポート

空の if ステートメント: 条件文が常に false と評価される if ステートメント空の else ステートメント: 常に実行されない else ステートメント空の try / catch / finally ブロック: 何もしない try / catch / finally ブロック


JavaScriptのfinallyブロック:安全な使い方とno-unsafe-finallyルールの活用

概要ルール名: no-unsafe-finallyデフォルト設定: error使用可能なオプション: なし問題点finally ブロックは、try ブロック内で発生した例外に関わらず、必ず実行されます。そのため、finally ブロック内で例外が発生しても、それが隠蔽されてしまい、プログラムの動作がおかしくなる可能性があります。


デバッグの時間を大幅短縮!no-unreachable-loopルールで到達不可能なループを撃退

ESLint の no-unreachable-loop ルールは、到達不可能なループを検出して警告するルールです。到達不可能なループとは、コード内の条件によって、ループが実行されることが絶対にないループを指します。問題点到達不可能なループは、コードの読みやすさを低下させ、潜在的なバグの原因となる可能性があります。例えば、無限ループと誤解される可能性があり、デバッグを困難にする可能性があります。


Morrow County のプログラマー必見!ESLint ルール "no-unused-labels" でコードを効率化

ESLint の "no-unused-labels" ルールは、JavaScript コードにおける未使用ラベルを検出して警告またはエラーとして報告します。ラベルとは、コード内の特定の箇所に名前を付けるために使用される構文です。ラベルは、break や continue などのジャンプ命令と組み合わせて、コードの流れを制御するために使用されます。


ネストされたコールバック関数はもう古い: max-nested-callbacks ルール徹底解説

max-nested-callbacks は、コード内のネストされたコールバック関数の最大数を制限する ESLint ルールです。このルールは、コードの読みやすさと保守性を向上させるために役立ちます。設定このルールは、オブジェクトリテラル形式で設定できます。以下のオプションが使用可能です。