LoginSignup
0
1

More than 3 years have passed since last update.

【javascript】プロミス

Last updated at Posted at 2020-07-19

この記事は以下の書籍を参考に執筆しました

プロミスでthenメソッドを呼び出すときには、引数として関数を渡し、この関数から返されるものはなんであってもチェンの次のthenの値になるが、

これには例外が1つある。

thenに渡された関数がプロミスを返す場合、そのプロミスは、値が解決または拒否されルマで待機してから同じことを行う。

function wait(milliseconds) {
  return new Promise((resolve) => {
    setTimeout(resolve, milliseconds)
  })
}

const time = new Date().getTime()
const logTime = () => {
  const seconds = (new Date().getTime() - time)
  console.log(seconds / 1000, 'have elapsed')
}

wait(5000)
  .then(() => {
    logTime();
    return wait(5000)
  })
  .then(() => {
    logTime();
    return wait(2000)
  })
  .then(() => {
    logTime();
  })

出典:入門JavaScriptプログラミング

5.003 "have elapsed"
10.009 "have elapsed"
12.012 "have elapsed"
  .then(() => {
    logTime();
     wait(5000)
  })

ここでは更に5秒待機するように設定されたプロミスを返す。
ここまでは合計で10秒待つことになる。
続いて2秒対して最後まで実行されるのに12秒かかる。

この方法がうまくいくのはthenに渡された関数がプロミスを返す場合に限られる。
下はプロミスを返さない場合。

function wait(milliseconds) {
  return new Promise((resolve) => {
    setTimeout(resolve, milliseconds)
  })
}

const time = new Date().getTime()
const logTime = () => {
  const seconds = (new Date().getTime() - time)
  console.log(seconds / 1000, 'have elapsed')
}

wait(5000)
  .then(() => {
    logTime();
     wait(5000)
  })
  .then(() => {
    logTime();
     wait(2000)
  })
  .then(() => {
    logTime();
  })

出典:入門JavaScriptプログラミング

5.002 "have elapsed"
5.002 "have elapsed"
5.002 "have elapsed"

wait関数が返されていないため、待機しない。

エラーキャッチ

thenの2つ目のパラメータにエラー時のコールバックを渡せるということは、数珠つなぎにした場合複数のエラーハンドラが必要なのか?

その必要はなく、プロミスが拒否された場合、そのプロミスは最初のエターハンドラが検出されるまでその上にあるプロミスをさかのぼる

Promise.resolve()
  .then(() => console.log('A'))
  .then(() => Promise.reject('X'))
  .then(() => console.log('B'))
  .then(null, err => console.log('caught:', err))
  .then(() => console.log('C'))

出典:入門JavaScriptプログラミング

出力はこうなる

A
caught: X
C

Bが出力されていないことに注目
Bの出力はrejectとエラーハンドラの間で発生している。
しかしCは出力されている。

プロミスが拒否されると、そのことがキャッチされるまで、
その後にあるプロミスは解決されないから。

プロミスの拒否がキャッチされた時点で
それよりも後ろにあるプロミスの解決が可能になる。

.then(null, err => console.log('caught:', err))

エラーハンドラを見てみると
1つの目引数にnullが渡されている。
このステップではエラーをキャッチすることが唯一の目的だから。

そのためのメソッドとしてcatchがあり、それで書き換えると以下のようになる。

Promise.resolve()
  .then(() => console.log('A'))
  .then(() => Promise.reject('X'))
  .then(() => console.log('B'))
  .catch(err => console.log('caught:', err))
  .then(() => console.log('C'))

出典:入門JavaScriptプログラミング

プロミスを拒否するためにPromise.rejectメソッドを使ったり、プロミス内部でrejectメソッドを呼ぶ必要はない。
Javascriptエラーが発生すればプロミスはすべて拒否される。

Promise.resolve()
  .then(() => {throw 'My Error'})
  .catch(err => console.log('catch:', err))//catch: My Error

出典:入門JavaScriptプログラミング

別の例を見てみる

ajax('/my-data.json')
  .then(
    res => {
      throw 'Some Error'
    },
    err => {
      console.log('First catcher:', err) //エラーがキャッチされない
    })
  .catch(err => {
    console.log('Second catcher:', err) //エラーがキャッチされる
  })

出典:入門JavaScriptプログラミング

thenに2つの関数を渡すと
1つ目の関数がプロミス解決時に実行
2つ目の関数がプロミス拒否時に実行される

しかし1つ目の関数でエラーが発生した場合、
2つ目の関数はそのエラーをキャッチしない

つまり、エラーをキャッチするには次のthenでキャッチしなくちゃいけない

参考文献

0
1
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
0
1