1. ホーム
  2. javascript

[解決済み] 早期解決・早期却下の後、戻る必要はありますか?

2022-03-16 01:58:18

質問

以下のようなコードがあったとします。

function divide(numerator, denominator) {
 return new Promise((resolve, reject) => {

  if(denominator === 0){
   reject("Cannot divide by 0");
   return; //superfluous?
  }

  resolve(numerator / denominator);

 });
}

もし、私の目的が reject を使う習慣を身につけるべきでしょうか。 return この後、すぐにでも?

解決方法は?

その return の目的は、拒絶の後に関数の実行を終了させ、その後に続くコードの実行を防止することです。

function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {

    if (denominator === 0) {
      reject("Cannot divide by 0");
      return; // The function execution ends here 
    }

    resolve(numerator / denominator);
  });
}

この場合 resolve(numerator / denominator); を実行することは、厳密には必要ではありません。しかし、将来起こりうる罠を防ぐためには、やはり実行を終了させることが望ましいでしょう。さらに、コードを不必要に実行しないようにすることも良い習慣です。

背景

プロミスは3つの状態のうちの1つになることができます。

  1. pending - 初期状態。保留状態から他の状態に移行することができる
  2. fulfilled - 操作に成功しました。
  3. rejected - 操作に失敗しました。

約束が実行されたり拒否されたりすると、その状態は無期限で維持されます(解決済み)。そのため、成立した約束を拒否しても、拒否された約束を成立させても、何の効果もありません。

この例のスニペットでは、拒否された後、約束は履行されましたが、拒否されたままになっています。

function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {
    if (denominator === 0) {
      reject("Cannot divide by 0");
    }

    resolve(numerator / denominator);
  });
}

divide(5,0)
  .then((result) => console.log('result: ', result))
  .catch((error) => console.log('error: ', error));

では、なぜ戻る必要があるのでしょうか?

解決したプロミスの状態を変更することはできませんが、拒否したり解決したりしても、関数の残りの部分の実行が停止することはありません。この関数には、混乱を招くような結果を生むコードが含まれている可能性があります。たとえば、以下のようなものです。

function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {
    if (denominator === 0) {
      reject("Cannot divide by 0");
    }
    
    console.log('operation succeeded');

    resolve(numerator / denominator);
  });
}

divide(5, 0)
  .then((result) => console.log('result: ', result))
  .catch((error) => console.log('error: ', error));

たとえ今この関数がそのようなコードを含んでいなくても、これは将来起こりうる罠を作り出しています。将来のリファクタリングでは、プロミスが拒否された後もコードが実行されるという事実を無視する可能性があり、デバッグが困難になります。

resolve/reject の後に実行を停止する。

これはJSの標準的な制御フローのものです。

  • の後に戻ります。 resolve / reject :

function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {
    if (denominator === 0) {
      reject("Cannot divide by 0");
      return;
    }

    console.log('operation succeeded');

    resolve(numerator / denominator);
  });
}

divide(5, 0)
  .then((result) => console.log('result: ', result))
  .catch((error) => console.log('error: ', error));

  • で返す。 resolve / reject - コールバックの戻り値は無視されるので、reject/resolve文を返すことで1行を節約できる。

function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {
    if (denominator === 0) {
      return reject("Cannot divide by 0");
    }

    console.log('operation succeeded');

    resolve(numerator / denominator);
  });
}

divide(5, 0)
  .then((result) => console.log('result: ', result))
  .catch((error) => console.log('error: ', error));

  • if/elseブロックを使用する。

function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {
    if (denominator === 0) {
      reject("Cannot divide by 0");
    } else {
      console.log('operation succeeded');
      resolve(numerator / denominator);
    }
  });
}

divide(5, 0)
  .then((result) => console.log('result: ', result))
  .catch((error) => console.log('error: ', error));

のいずれかを使用するのが望ましいと思います。 return というオプションは、コードが平坦になるためです。