eyrin.jp

try/catchではなくawait/catchを使おう

async関数はファイルの読み込みや書き込みといった、エラーの可能性を伴うような関数に使われることが多い。この際のエラーハンドリングは通常try/catchパターンで行われる(私もそうしてきた)。

しかし、この方法にはデメリットもある。

  • 先に結果を保持するための変数をletで宣言するのが気持ち悪い
  • 面倒臭くなってtry/catchのブロックの中身が肥大化しがち

などである。

そもそも、tryの中身をデカくして、なんでもcatchしてしまうようなコードを書くのは好ましくない。エラーを握りつぶしてしまう可能性があるからである。

個人的には、try/catchでエラーハンドリングをするよりも、エラーが発生する可能性のある箇所ごとにawait/catchでエラーハンドリングをして、早期リターンなどで対処する、といったコードの方が適切に思う。

await/catchパターンの利点

  • 関数の結果をconstで保持できる
  • エラーが発生したら適切に処理した後、早期リターンで安全に終了できる
  • Goのエラーハンドリングみたいで個人的に好き

コード例

// 1/2の確率でエラーを返す関数
const func = async () => {
  if (Math.random() > 0.5) {
    throw new Error("error");
  }
  return "success";
};

// await/catchパターン
const result = await func().catch((err) => err.message);
console.log(result);

// thenでも書けるよ(TypeScriptのPromiseLike型とかで役に立つかも)
const resultWithThen = await func().then(
  (data) => data,
  (err) => err.message,
);

// 早期リターンで関数を正常に終了
(async () => {
  const earlyReturn = await func().catch(() => undefined);
  if (!earlyReturn) {
    return;
  }
  console.log(earlyReturn);
})();