9
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Promiseでalwaysする方法

Last updated at Posted at 2016-03-17

簡単で、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)) // 実行されない
9
12
0

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
  3. You can use dark theme
What you can do with signing up
9
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?