かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

JavaScript (ES2015) 今更のPromise (2) Promiseが返された後の処理のメモ

前回のあらすじ

通常のPromiseを返す関数で明示的にresolve()reject()returnしてないと関数の終わりまで実行されるのでは?と思い調べてみました。

明示的に resolve/reject がreturnされていない場合

function myFunc(a, b = 0) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if(!a) {
        reject( `Error a is ${a}` )
      }
      let res = (a + b) * 2
      console.log(`(${a} + ${b}) * 2 = ${res}`)
      resolve( res )
    }, 10)
  })
}

myFunc(0)
.then((res1) => console.log(res1))
.then((res2) => console.log('CHAIN!!', res2))
.catch((error) => console.log(error))
// => (0 + 0) * 2 = 0
// => Error a is 0

やはりrejectが呼ばれた後も、関数の中は最後まで実行されていました。
恐らくresolve( res )も実行されているけど、元の呼び出し元では先にrejectが返っているので、再度thenに処理が流れたり、次のthenが呼び出されることもなく無視するようになってるっぽい。
ただresolve, rejectしてもその後の処理が無駄に実行されるので、Promiseオブジェクトを返す関数内ではそれ以上処理が必要ないならreturn resolve()return reject()とした方が良さそう。

並列処理 Promise.all, Promise.race は処理が返っても残りの処理は実行され続けている。

Promise.allでエラーが返ったり、Promise.raceで最初の値が返されても、呼び出していた処理は引き続き実行されているようです。
task

const task1 = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('> TASK-1')
      resolve('task1')
    }, 20)
  })
}

const task2 = () => {
  return new Promise((resolve, rejecy) => {
    setTimeout(() => {
      console.log('> TASK-2')
      resolve('task2')
    }, 5)
  })
}

const task3 = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('> TASK-3')
      reject('REJECT TASK3')
    }, 10)
  })
}

Promise.all

Promise.all([task1(), task2(), task3()])
.then((res) => {
  console.log('>>> Promise.all', res)
})
.catch((error) => {
  console.log('>>> Promise.all ERROR')
})
// >> TASK-2
// >> TASK-3
// >>> Promise.all ERROR
// >> TASK-1

task3rejectされcatchに処理が流れているが、呼び出されたtask1はそのまま実行されている

Promise.race

Promise.race([task1(), task2(), task3()])
.then((res) => {
  console.log('>>> Promise.race', res)
})
.catch((error) => {
  console.log('>>> Promise.race ERROR')
})
// >> TASK-2
// >>> Promise.race task2
// >> TASK-3
// >> TASK-1

task2の処理が完了しても呼び出されていたtask1, task3は引き続き実行はされている

APIとかでエラーがあればエラーを返して処理をまるっと終了させたいような場合はprocess.exit(1)とかでプロセスを終了させてしまうのが良いのかな? (API作ったこと無いから正解かどうか判断しかねるけど)