【Node.js】return await の紛らわしい注意点

Eslint には no-return-await というルールがある。Standard JS にも採用されているルールだ。このルールは、return await に警告を出す。

async function foo() {
    return await bar()
}

しかし、常に return await しないべきかというとそうでもなくて、必要な場合もある。

それを確かめるべく、まずはエラーを投げる async 関数を作る。

const failAsync = async () => {
  throw 'Failed'
}

これを return await する場合としない場合の関数を書いてみる。

const returnAwait = async () => {
  try {
    return await failAsync()
  } catch (error) {
    throw 'returnAwait error'
  }
}

const noReturnAwait = async () => {
  try {
    return failAsync()
  } catch (error) {
    throw 'noReturnAwait error'
  }
}

これらは実行時に何か違いがあるだろうか。

;(async () => {
  try {
    await returnAwait()
  } catch (error) {
    console.error(error)
  }
  try {
    await noReturnAwait()
  } catch (error) {
    console.error(error)
  }
})()

実行したときの出力はこうなる。

returnAwait error
Failed

おわかりのとおり、noReturnAwait() の中では failAsync() のエラーを捕捉できていない。

return したプロミスがエラーを投げる可能性があるとき、return await しないとエラーを捕捉できないというわけだ。

このように、return await をするかどうかで挙動が異なる場合がある。

Eslint の no-return-await ルールではこれを考慮して、return awaittry {} で包まれているときには警告を出さない。