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 ルールです。これは、オブジェクトリテラル記法の方が簡潔で読みやすいコードになるためです。ルール設定



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

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


テンプレートリテラルを使いこなせ!ESLintの prefer-template ルールでコードの可読性を向上させる

prefer-templateは、ESLintのRulesの一つで、文字列の連結にテンプレートリテラルを使用することを推奨するルールです。テンプレートリテラルは、文字列の連結をより簡潔で分かりやすく記述できるため、コードの可読性向上に役立ちます。


Web開発者のためのセキュリティとパフォーマンスのヒント:ESLintのno-script-urlルール

セキュリティjavascript: スキーマを含む URL は、悪意のあるコードを実行するために使用される可能性があります。例えば、以下のような攻撃が可能です。クロスサイトスクリプティング (XSS):攻撃者がユーザーのブラウザに悪意のあるコードを注入し、ユーザーの操作を乗っ取ったり、個人情報を盗んだりすることができます。


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

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



コードの可読性と保守性を向上させる!ESLintルール「func-name-matching」徹底解説

このルールは、以下の2つのオプションを設定できます。"never":関数名が変数名またはプロパティ名と一致しない場合、エラーが発生します。"always":関数名が変数名またはプロパティ名と一致している場合、警告が発生します。デフォルトでは、"never"が設定されています。


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

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


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

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


ESLint ルール「no-multi-assign」:初心者でも安心!分かりやすい解説

ESLintのルール「no-multi-assign」は、変数に複数回代入することを制限するルールです。これは、コードの読みやすさや意図の明確さを向上させるために役立ちます。問題点変数に複数回代入すると、コードの意味が分かりにくくなります。例えば、以下のコード:


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

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