search
LoginSignup
35

More than 5 years have passed since last update.

posted at

updated at

Organization

async await に書き換えて、Promiseと 同期による例外の区別でハマった

ハマった

元のコード

// async function の中
try {
  load().then(data => {
    console.log(data)
  }).catch(e => {
    // ...
  })
} catch (e) {
  // ... 例外処理
}

わかりやすく簡単にしている。実際にはもっと複雑なコードだった。Promise にすれば
try と catch を一本化して綺麗にできるやん!と思っていた。最初は。

書き換えた

// async function の中
try {
  const data = await load()
  console.log(data)
} catch (e) {
  // ... 例外処理
}

catch が一個減ってリファクタできたーと思っていた。確かに異なる例外処理のブロックが減ってしまっていたが、どうせ何かしらのデッドコードだろと思って消してしまった。

注: 意味的に変わってしまっているが、実際にはすごく複雑なコードで、大きな方のtryは別の例外をキャッチしていると思っていた…

何が起こったか

catch に来てた部分が、Promise の
UnhandledRejectionError になってしまっていた(のにしばらく気づかなかった)。

ここで、状況を述べておくと、 load() はライブラリが提供してた関数で、Promiseを返すことは知っていたが、実装には詳しくなかった。これがハマる理由になった。

挙動をちゃんと追うと、ここの load()同期的な例外 または Promise を返す という実装だった。期待していたのは Promise の resolve or reject だったので、ミスマッチがあったというわけ。

どう直したか

// async function の中
try {
  const loading = load()
  try {
    const data = await loading
    console.log(data)
  } catch (e) {
    // 非同期例外
  }
} catch (e) {
  // 同期例外
}

えーー!!ってコードになってしまった。でもこれが元々期待されてた挙動的に正しい…。

反省

  • async/await の中でも同期例外と非同期例外を区別する
  • 自分がPromiseの関数を実装するときは Promiseのインターフェースに押し込めるようしたいと思った
  • 例外パターンに対するテストは常に書こう

以上、これで2日分ほどハマった現場よりの報告でした。

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
What you can do with signing up
35