Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

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

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

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

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

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

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

await/catch パターン

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

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

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

/// ↓ ↓ ↓

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

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

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を組み合わせることができます。
これは、いちいち変数を用意するまでもない(むしろ冗長な)連続した処理に活用できるでしょう。

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

// ↓ ↓ ↓

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

まとめ

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

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

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

twitterおよびはてブのコメントの反映

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

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

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

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を使ってみます。

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のチェインについて見てみます。

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を繋げる書き方も可能です。

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://twitter.com/Linda_pp/status/731315618935267328

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

akameco
シュレーディンガーの社会人.js
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした