async関数においてtry/catchではなくawait/catchパターンを活用する


ご存知の通り、async/awaitはとても美しく明快であり、JS界隈の誰もが待ち望んだ機能であります。

```js
async function f() {
 const x = await g()
}
```

async/awaitのエラーハンドリングはtry/catchで行うのが一般的です。
しかし、これは複数のawaitを使い、それぞれ別のエラーハンドリングを行いたい場合など、冗長になりがちです。
そして、特に気に入らないのが、tryのスコープ外で非同期関数の戻り値を使う場合、letを使う必要があるところです。

```js
let name = 'ゲスト'
try {
  name = await getName()
} catch (err) { }

console.log(`ようこそ ${name}さん`)
```

そこで、await/catchパターンを活用して、これを改善してみましょう。

##await/catch パターン
上記をawait/catchパターンで書き換えてみます。

```js
let name = 'ゲスト'
try {
  name = await getName()
} catch (err) { }

console.log(`ようこそ ${name}さん`)
// => ようこそ ゲストさん

/// ↓ ↓ ↓

const name = await getName().catch(() => 'ゲスト')
console.log(`ようこそ ${name}さん`)
// => ようこそ ゲストさん
```

グレート！
あの忌々しいletが消え去り、constにより平和が訪れました。ああ、不変性の美しきかな。なにより、ネストが減るのがいいですね。
もう一つパターンを見てみましょう。
複数のasync関数のエラーをそれぞれ別々にハンドリングする必要ある場合です。

```js
try {
  await f()
} catch (err) {
  handleErr1(err)
}
try {
  await g()
} catch (err) {
  handleErr2(err)
}

// ↓ ↓ ↓

await f().catch(handleErr1)
await g().catch(handleErr2)
```

完璧です。
完全に冗長な記述が消え、シンプルなコードになりました。
結局のところ、**async関数はPromiseを返す関数でしかなく、awaitはPromiseの解決を待つので、catchをそのまま使えるわけです。**


## Tips
もちろんawaitとthenを組み合わせることができます。
これは、いちいち変数を用意するまでもない(むしろ冗長な)連続した処理に活用できるでしょう。

```js
const x1 = await func()
const x2 = await filter1(x1)
const x3 = await filter2(x2)

// ↓ ↓ ↓

const x = await func().then(filter1).then(filter2)
```


## まとめ
await catchパターンを活用することで、コードが簡潔になることがわかりました。
何かあれば、コメント欄またはツイッターにて議論しましょう。


<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">async/awaitのcatchパターン。async関数はpromiseを返す関数でしかないので、catchをそのまま使える。 <a href="https://t.co/cm3v9Ugj85">pic.twitter.com/cm3v9Ugj85</a></p>&mdash; 撃殺コスモ地獄拳 (@akameco) <a href="https://twitter.com/akameco/status/899861822861262848">2017年8月22日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-conversation="none" data-lang="ja"><p lang="ja" dir="ltr">APIの異常系をテストするときawait catchパターンを使うと便利 <a href="https://t.co/wqb1aYWPAb">pic.twitter.com/wqb1aYWPAb</a></p>&mdash; 撃殺コスモ地獄拳 (@akameco) <a href="https://twitter.com/akameco/status/900078985320595456">2017年8月22日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>


本記事は、以下からの転載です。


[async関数においてtry/catchではなくawait/catchパターンを活用する – 赤芽 – Medium](https://medium.com/@akameco/async%E9%96%A2%E6%95%B0%E3%81%AB%E3%81%8A%E3%81%84%E3%81%A6try-catch%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%8Fawait-catch%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E3%82%92%E6%B4%BB%E7%94%A8%E3%81%99%E3%82%8B-7dfda451043)



## twitterおよびはてブのコメントの反映
情報の精度を上げるため、はてブやtwitterでの意見を出来る範囲で反映していきます。

### 💬 たまにやるけど、エラー握りつぶしながら動きそうで怖い from はてブ

try/catchでもcatch使う場合でも、エラーをハンドリングするわけですから、握りつぶしながら動くという表現はよくわかりませんが、catch内でErrorをthrowした場合の処理について見てみます。

```js
function asyncFunc() {
  return Promise.reject(new Error('throw from asyncFunc'))
}

async function main() {
  try {
    await asyncFunc().catch(err => {
      console.log(err)
      throw new Error('throw from await/catch')
    })
  } catch (err) {
    console.log(err)
  }
}

main()


// => throw from asyncFunc
// => throw from await/catch
```

catch内でthrowした場合、その上のtry/catchで補足できます。
Promise.rejectを使ってみます。

```js
try {
  await asyncFunc().catch(err => {
    console.log(err)
    return Promise.reject(new Error('throw from await/catch'))
  })
} catch (err) {
  console.log(err)
}


// => throw from asyncFunc
// => throw from await/catch
```

次は、catchのチェインについて見てみます。

```js
await asyncFunc()
  .catch(err => {
    console.log(err.message)
    return Promise.reject(new Error('throw from await/catch'))
  })
  .catch(err => {
    console.log(err.message)
  })



// => throw from asyncFunc
// => throw from await/catch
```

いずれのパターンもPromiseを扱い場合と同じようにハンドリングできるようです。
また、promiseのチェインは途中でcatchすることも可能なので、以下のような最後にthenを繋げる書き方も可能です。

```js
const result = await asyncFunc()
  .catch(err => {
    console.log(err.message)
    return Promise.reject(new Error('throw from await/catch'))
  })
  .catch(err => {
    console.log(err.message)
  })
  .then(() => 1)

console.log(result)

// => throw from asyncFunc
// => throw from await/catch
// => 1
```

### 💬 確かに素晴らしいんだけど、constよりletの方が見やすいし好きなんでツライ

![CiYnrgcVEAEk1Kk.jpg](https://qiita-image-store.s3.amazonaws.com/0/15319/2d94d237-6e08-9b0c-db5c-181f5837de25.jpeg)

https://twitter.com/Linda_pp/status/731315618935267328

完全に気持ちを代弁する画像をお借りしました。