前回のあらすじ
通常の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
task3でreject
され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作ったこと無いから正解かどうか判断しかねるけど)