読み込み中 %

アイコン

javascriptの非同期処理でcatch()を連鎖させる方法

taikishiino
2020/05/27

javascriptの非同期処理で、一旦別のメソッドにてエラーレスポンスを受け取った後に、続けて呼び出し元にエラーレスポンスとして返却したいといった時があり、Promiseawait/catchの仕様を改めて振り返ってみたのでメモとして記事にします。

Promiseを使用する方法

処理の流れ

  1. rejectPromiseFunc()でrejected状態のPromiseエラーを返す
  2. promiseFunc1のcatch()でエラーを受け取り、再度rejected状態にしたPromiseエラーを返す
  3. promiseFunc2のcatch()も2.と同様
  4. 呼び出し元のcatch()で、rejectPromiseFunc()で発生したエラーを受け取ることができる
function rejectPromiseFunc() {
  console.log("===> Call rejectPromiseFunc")
  return new Promise((resolve, reject) => {
    const error = new Error("エラーが発生しました")
    setTimeout(() => {
      reject(error)
    }, 500);
  })
}

function promiseFunc1() {
  console.log("promiseFunc1")
  return new Promise((resolve, reject) => {
    rejectPromiseFunc()
      .then(response => {
        console.log("then[1]: " + response)
        resolve(response)
      })
      .catch(error => {
        console.log("catch[1]: " + error)
        reject(error)
      })
  })
}
function promiseFunc2() {
  console.log("promiseFunc2")
  return new Promise((resolve, reject) => {
    promiseFunc1()
      .then(response => {
        console.log("then[2]: " + response)
        resolve(response)
      })
      .catch(error => {
        console.log("catch[2]: " + error)
        reject(error)
      })
  })
}

promiseFunc2()
  .then(response => {
    console.log("then[3]: " + response)
  })
  .catch(error => {
    console.log("catch[3]: " + error)
  })
実行結果
promiseFunc2
promiseFunc1
===> Call rejectPromiseFunc
catch[1]: Error: エラーが発生しました
catch[2]: Error: エラーが発生しました
catch[3]: Error: エラーが発生しました

async functionを使用する方法

async functionについて

  • async functionは呼び出されるとPromiseを返す
  • async functionが値をreturnした場合、Promiseは戻り値をresolveする
  • async functionが例外や何らかの値をthrowした場合はその値をrejectする

処理の流れ

  1. rejectPromiseFunc()でrejected状態のPromiseエラーを返す
  2. asyncFunc1のcatch()でエラーを受け取り、throwにより例外を作り出し、再度rejected状態にしたPromiseエラーを返す
  3. asyncFunc2のcatch()も2.と同様
  4. 呼び出し元のcatch()で、rejectPromiseFunc()で発生したエラーを受け取ることができる
function rejectPromiseFunc() {
  console.log("===> Call rejectAsyncFunc");
  const error = new Error("エラーが発生しました")
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(error)
    }, 500);
  })
}

async function asyncFunc1() {
  console.log("asyncFunc1")
  const result = await rejectAsyncFunc()
    .catch(error => {
      console.log("await/catch[1]: " + error)
      throw error
    })
  console.log("async/success[1]: " + result)
  return result
}
async function asyncFunc2() {
  console.log("asyncFunc2")
  const result = await asyncFunc1()
    .catch(error => {
      console.log("await/catch[2]: " + error)
      throw error
    })
  console.log("async/await[2]: " + result)
  return result
}

asyncFunc2()
  .then(response => {
    console.log("then: " + response)
  })
  .catch(error => {
    console.log("catch: " + error)
  })
実行結果
asyncFunc2
asyncFunc1
===> Call rejectAsyncFunc
await/catch[1]: Error: エラーが発生しました
await/catch[2]: Error: エラーが発生しました
catch: Error: エラーが発生しました

実際に使用したパターン

axiosなどのAPIクライアントでエラーレスポンスを共通処理としてハンドルする時に使用しました。

axios.interceptors.response.use(
  response => {
    return Promise.resolve(response)
  },
  error => {
    const errorResponse = error.response
    if (errorResponse && errorResponse.data && errorResponse.data.hoge_flg) {
      // アプリケーション共通で行いたいエラーハンドリング
      const msg = errorResponse.data.error
      notification(msg)
      location.href = `/hogehoge`
      return
    }
    // コンポーネント側でエラーハンドリングを行う
    return Promise.reject(error)
  }
)