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

Promiseでalwaysする方法

More than 3 years have passed since last update.

簡単で、catch以降に処理を書くとエラー発生の有無に関わらず実行される。jsbin

Promise.resolve()
  .then(() => console.log('通常時: 1'))
  .catch(err => {})
  .then(() => console.log('通常時: 2'))

// -> 通常時: 1
//    通常時: 2

Promise.reject(new Error())
  .then(() => console.log('エラー時: 実行されない'))
  .catch(err => {})
  .then(() => console.log('エラー時: 1'))

// -> エラー時: 1

どのようなケースで使うか

あるスコープで発生したゴミをそのスコープ内で掃除したいというケースなどに有用。jsbin

const example = () => {
  const p = Promise.resolve()
    .then(() => console.log('ゴミが発生'))
    .then(() => {
      console.log('エラーが発生')
      return Promise.reject(new Error)
    })
    .then(() => console.log('通常なら実行される'))  // スキップされる
    .catch(err => {})
    .then(() => console.log('ゴミを処理'))          // エラーの有無にかかわらず実行される
  return p
}

example()

捕捉したエラーを変数に確保し、共通処理後にリジェクトするパターン

example()の呼び出し元でエラーハンドリングを行いたいことがある。
スコープ内でcatchしたエラーを共通処理後にもう一度rejectしてあげると、以降のthenはスキップされ次に現れるcatchでエラーを捕捉できる。jsbin

const example = () => {
  let error
  const p = Promise.resolve()
    .then(() => console.log('ゴミが発生'))
    .then(() => {
      console.log('エラーが発生')
      return Promise.reject(new Error)
    })
    .then(() => console.log('通常なら実行される'))  // スキップされる
    .catch(err => error = err)                      // キャッチしたエラーを変数に格納
    .then(() => {
      console.log('ゴミを処理')                     // エラーの有無にかかわらず実行される
      if (error) {
        return Promise.reject(error)                // エラーがある場合はrejectする
      }
    })
  return p                                          // Promiseインスタンスを返却
}

example()
  .then(() => console.log('exampleが通常なら実行される'))       // スキップされる
  .catch((err) => console.log('exampleがエラーなら実行される')) // 実行される

捕捉したエラーを共有処理に渡し、共通処理後にリジェクトするパターン

次のように、catchで捕捉したエラーをreturnし、次のthenに渡すというエラーを変数に確保しないパターンもある。jsbin

const example = () => {
  return Promise.reject(new Error())
    .catch(err => err)
    .then((err) => {
      if (err) {
        return Promise.reject(err)
      }
    })
}

example()
  .catch((err) => console.log(err)) // 実行される

一時確保用の余計な変数がなくなって良さそうに見えるけど、catch前のチェーンで何かを渡している場合は、エラーが起こらないとcatch後のthenにその値が渡ってしまい、エラーではないのにrejectしてしまう。jsbin

const example = () => {
  return Promise.resolve('エラーではない何か')
    .catch(err => err)
    .then((err) => {
      console.log(err)              // -> 'エラーではない何か'
      if (err) {
        return Promise.reject(err)
      }
    })
}

example()
  .catch((err) => console.log(err)) // -> 'エラーではない何か'

これは意図しない挙動で、catch後のthenに渡ってくる引数がエラーなのかを判定しなければならない。jsbin

const example = () => {
  return Promise.resolve('エラーではない何か')
    .catch(err => err)
    .then((arg) => {
      console.log(arg)              // -> 'エラーではない何か'
      if (arg instanceof Error) {
        return Promise.reject(arg)
      }
    })
}

example()
  .catch((err) => console.log(err)) // 実行されない
minodisk
冷やし中華はじめました
resily
OKR導入・運用改善コンサルティングと、自社開発のクラウドOKRツール『Resily』を展開するスタートアップ
https://resily.com/
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
ユーザーは見つかりませんでした