JavaScript
js
promise

async/awaitでErrorをGoっぽく書きたかった

非同期のエラー処理

フロントでは非同期処理でエラーを捌くことが多い。
普通だったら Promisecatch すればいいが・・・

複雑なエラー処理

複数の非同期直列 で実行したい」
こういうとき、どうなるか

Promise でやる

これを見て欲しい。

function foo() {
  return new Promise((resolve, reject) => {
    let result_1;
    fetch('/foo')
      .catch(() => {
        reject({ errorType: 1 });
        return new Promise(() => {});
      })
      .then(_result_1 => {
        result_1 = _result_1;
        return fetch('/bar?result_1=' + result_1);
      })
      .catch(() => {
        reject({ errorType: 2 });
        return new Promise(() => {});
      })
      .then(result_2 => {
        resolve({
          messaga: 'fetch complete',
          result_1,
          result_2,
        });
      });
  });
}

控え目に言ってナニコレ状態。
解説をつけたのがこちら。

function foo() {
  return new Promise((resolve, reject) => {
    let result_1;
    fetch('/foo')
      .catch(() => {
        // fetch('/foo') のエラー処理
        reject({ errorType: 1 });

        // ここで処理止めたいが・・・
        // 何もしないと次の then(1) へ進んでしまう
        // throwすると次の catch(2) へ進んでしまう
        // 苦肉の策、永遠にresolveしないPromiseを返して止める・・・
        return new Promise(() => {});
      })
      .then(_result_1 => {
        // result_1 を最後に返すためにわざわざlet
        result_1 = _result_1;
        // (1) 2つ目のfetch開始
        return fetch('/bar?result_1=' + result_1);
      })
      .catch(() => {
        // (2) fetch('/bar') のエラー処理
        reject({ errorType: 2 });

        // 苦肉の策、永遠にresolveしないPromiseを返して止める・・・
        return new Promise(() => {});
      })
      .then(result_2 => {
        resolve({
          messaga: 'fetch complete',
          result_1,
          result_2,
        });
      });
  });
}

つらい

async/await でやる

async/await だと自然なコードにできて幸せ

async function foo() {
  let result_1;
  try {
    result_1 = await fetch('/foo');
  } catch (e) {
    throw { errorType: 1 };
  }

  let result_2;
  try {
    result_2 = await fetch('/bar?result_1=' + result_1);
  } catch (e) {
    throw { errorType: 2 };
  }

  return {
    messaga: 'fetch complete',
    result_1,
    result_2,
  };
}

いい感じ。
しかし try/catch のために let を使わなきゃいけないし、インデントも増える。
try/catch 使ったら当たり前のごく普通のコードだけど。
try/catch の見た目は慣れない。

Go みたいに書きたい

個人的に Go のエラーの書き方が好きなので、
Go みたいにエラー書けたらいいのになぁあああああ!!!
という願望がある。

イメージ

イメージではこんな感じに書きたい

// イメージです
async function foo() {
  const result_1, err = await fetch('/foo');
  if(err){
    throw { errorType: 1 };
  }

  const result_2, err = await fetch('/bar?result_1=' + result_1);
  if(err){
    throw { errorType: 2 };
  }

  return {
    messaga: 'fetch complete',
    result_1,
    result_2,
  };
}

Go っぽく書いた

async function foo() {
  const result_1 = await fetch('/foo').catch(e => e);
  if (result_1 instanceof Error) {
    throw { errorType: 1 };
  }

  const result_2 = await fetch('/bar?result_1=' + result_1).catch(e => e);
  if (result_2 instanceof Error) {
    throw { errorType: 2 };
  }

  return {
    messaga: 'fetch complete',
    result_1,
    result_2,
  };
}

イケるやん
個人で書くならこの書き方したい。

けど、少しトリッキーだから、
やっぱtry/catchで書くのがいいですかね。