10
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-04-09

非同期のエラー処理

フロントでは非同期処理でエラーを捌くことが多い。
普通だったら 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で書くのがいいですかね。

10
8
9

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?