質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

3回答

2140閲覧

PromiseをネストしないでPromiseをチェーンしようとしているがうまくいかない

murabito

総合スコア108

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

1クリップ

投稿2019/02/17 06:20

編集2019/02/17 06:22

1つの非同期処理が成功した時に、後続の非同期処理を行いたいのですが、Promiseをネストせずに書こうとすると上手くいきません。

前提として、最初の非同期処理と後続の非同期処理では成功した時も、エラーが発生した時もそれぞれ異なる処理を行います。

また、async awaitを使わないというのも前提となります。

Promiseでネストさせるのは宜しくないようなので、ネストを回避した書き方を身に付けたいのですが、例外が発生する場合に上手くかけません。

正しい書き方をご教示頂けますと幸いです。

両方の非同期処理がresolveされるケース

ネストした書き方

const async1 = () => { return new Promise((resolve, reject) => { setTimeout(() => { return resolve('async1 success') }, 1000) }) } const async2 = () => { return new Promise((resolve, reject) => { setTimeout(() => { return resolve('async2 success') }, 1000) }) } async1() .then(result => { console.log('then1:', result) return async2() .then(result => console.log('then2:', result)) .catch(error => console.error('catch2:', error)) }) .catch(error => console.error('catch1:', error))

ネストさせない書き方

const async1 = () => { return new Promise((resolve, reject) => { setTimeout(() => { return resolve('async1 success') }, 1000) }) } const async2 = () => { return new Promise((resolve, reject) => { setTimeout(() => { return resolve('async2 success') }, 1000) }) } async1() .then(result => { console.log('then1:', result) return async2() }) .catch(error => console.error('catch1:', error)) .then(result => console.log('then2:', result)) .catch(error => console.error('catch2:', error))

期待するアウトプット

then1: async1 success then2: async2 success

実際のアウトプット(OK!)

この場合は、ネストする書き方もネストしない書き方も期待したアウトプットになっている。

then1: async1 success then2: async2 success

最初の非同期処理がresolveされ、後続の非同期処理がrejectの場合

ネストされた書き方

const async1 = () => { return new Promise((resolve, reject) => { setTimeout(() => { return resolve('async1 success') }, 1000) }) } const async2 = () => { return new Promise((resolve, reject) => { setTimeout(() => { return reject('async2 error') }, 1000) }) } async1() .then(result => { console.log('then1:', result) return async2() .then(result => console.log('then2:', result)) .catch(error => console.error('catch2:', error)) }) .catch(error => console.error('catch1:', error))

ネストさせない書き方

const async1 = () => { return new Promise((resolve, reject) => { setTimeout(() => { return resolve('async1 success') }, 1000) }) } const async2 = () => { return new Promise((resolve, reject) => { setTimeout(() => { return reject('async2 error') }, 1000) }) } async1() .then(result => { console.log('then1:', result) return async2() }) .catch(error => console.error('catch1:', error)) .then(result => console.log('then2:', result)) .catch(error => console.error('catch2:', error))

期待するアウトプット

then1: async1 success catch2: async2 error

※ 最初の非同期処理と異なるエラーハンドリングが後続の非同期処理でできれば、実際は2つ目のcatchブロックでハンドリングすることは必須ではない。

実際のアウトプット(NG!)

この場合は、ネストされた書き方は期待通りにアウトプットを得られるが、ネストさせない書き方は間違っているのか以下のアウトプットになってしまう。

then1: async1 success catch1: async2 error then2: undefined

最初の非同期処理でrejectになった場合

ネストする書き方

const async1 = () => { return new Promise((resolve, reject) => { setTimeout(() => { return reject('async1 error') }, 1000) }) } const async2 = () => { return new Promise((resolve, reject) => { setTimeout(() => {}, 1000) }) } async1() .then(result => { console.log('then1:', result) return async2() .then(result => console.log('then2:', result)) .catch(error => console.error('catch2:', error)) }) .catch(error => console.error('catch1:', error))

ネストさせない書き方

const async1 = () => { return new Promise((resolve, reject) => { setTimeout(() => { return reject('async1 error') }, 1000) }) } const async2 = () => { return new Promise((resolve, reject) => { setTimeout(() => {}, 1000) }) } async1() .then(result => { console.log('then1:', result) return async2() }) .catch(error => console.error('catch1:', error)) .then(result => console.log('then2:', result)) .catch(error => console.error('catch2:', error))

期待するアウトプット

catch1: async1 error

実際のアウトプット(NG!)

catch1: async1 error then2: undefined

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

最初の非同期処理がresolveされ、後続の非同期処理がrejectの場合

JavaScript

1async1() 2 .then(result => { 3 console.log('then1:', result) 4 return async2() 5 }) 6 .catch(error => console.error('catch1:', error)) 7 .then(result => console.log('then2:', result)) 8 .catch(error => console.error('catch2:', error))

これはasync1とasync2を立て続けに実行した後に、
どちらかが失敗したらcatch1のエラーログが出力するように書かれている。
そして最後の.then(result => console.log('then2:', result))は絶対に失敗しないのでcatch2のエラーログは多分一生拝めない。

つまり言ってる事と書いてるコードが違うってことね。
正確にはこうかな?

JavaScript

1async1() 2 .catch(error => console.error('catch1:', error)) 3 .then(result => { 4 console.log('then1:', result) 5 return async2() 6 }) 7 .catch(error => console.error('catch2:', error)) 8 .then(result => console.log('then2:', result))

こうすればasync1で失敗すればcatch1が出るし、
async2で失敗すればcatch2が出るはず。

投稿2019/02/17 15:05

miyabi-sun

総合スコア21158

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

murabito

2019/02/18 12:56

実はcatchブロックをthenより先に持ってくるのも試していたのですが、これだと、エラーが発生した時にまずcatchに入って、そのあと、catchがpromiseを返すからなのか、thenにその後、移ってしまうみたいなのですよね。catchでプロミスチェーンを切れれば良いのですが。
murabito

2019/02/19 12:46

時間を置いて考えてみました。掲載いただいたコードの1つ目のcatchブロックで、`return Promise.reject(error)`してあげれば、期待通り、thenブロックには移らない。しかし、最後のcatchブロックに移ってしまうので、そこで渡ってきたエラーオブジェクト参照して、すでにハンドリング済みのものであれば何もしないという対応でひとまず行ってみようと思いました。
guest

0

必要としているのは逐次処理で、下記リンク先が参考になると思います。

Re: murabito さん

投稿2019/02/17 06:48

think49

総合スコア18164

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

murabito

2019/02/17 08:05

リンク先拝見いたしました。サンプルコードがcatch句1つのものなのですが、今回の私のケースのように、1つ目の非同期処理と2つ目の非同期処理で異なるエラーハンドリングを行う場合はどのようにすれば良いのでしょうか?単純な逐次処理であれば、質問文の最初の例の簡略版になりますが、```async1().then(async2).catch(console.error)```のようにすれば良いのかなとは思いますが。
think49

2019/02/17 08:07

どのように…って、then,catchがある逐次処理のコードなので、そのまま実装すれば良いと思いますが、試してみましたか?
think49

2019/02/17 08:22

ああ、元のコードでは catch() が共通処理になっているのを危惧していたのですか 再帰的に then() しているコードがあるので、そこで .catch() を加える修正を行えばよいと思います。
guest

0

javascriot

1.then(A).catch(B).then(C)

catchで例外を発生されないという事は
例外が発生したが、正しくリカバリーできたとういう事なので
次のthenブロックが処理されます。

このような仕組みでなければ、例外が発生した時のリカバリーができないという事になります。

これを同期のような形で書くと分かりやすいと思います。

javascriot

1try{ 2 A 3} 4cathc(x){ 5 B // ここで例外を発生されなければ、何らかのリカバリーが出来たという事なので次のCを実行します。 6} 7 8C

この事を理解していないとPromiseのチェーンは難しいです。

これを踏まえて、あなたがやりたいのは以下になります

  1. async1、async2の例外は識別可能なものを例外として発生させる
  2. catchで上記の例外の種類により処理を変える

javascript

1try{ 2 async1(); 3 async2(); 4 console.log('success'); // ここで例外が発生する事もあるのでその場合はother 5}catch(e){ 6 if(e instanceof ErrorAsync1){ 7 console.log('error1') 8 } 9 else if(e instanceof ErrorAsync2){ 10 console.log('error2') 11 }else{ 12 console.log('other') 13 } 14}

これをPromiseで書くとこうなります。

javascript

1Promise.resolve() 2 .then(()=>async1()) 3 .then(()=>async2()) 4 .then(()=>{ 5 console.log('success') 6 }) 7 .catch((e)=>{ 8 if(e instanceof ErrorAsync1){ 9 console.log('error1') 10 } 11 else if(e instanceof ErrorAsync2){ 12 console.log('error2') 13 }else{ 14 console.log('other') 15 } 16 }); 17

ここで問題になるのがasync1もasync2も自分が修正できる領域ではない場合です
その場合、各処理をcatchして例外を変える処理が必要になるので以下のようになるでしょう。

javascript

1try{ 2 try{ 3 async1(); 4 }catch(e){ 5 throw new ErrorAsync1(); 6 } 7 try{ 8 async2(); 9 }catch(e){ 10 throw new ErrorAsync2(); 11 } 12 console.log('success'); // ここで例外が発生する事もあるのでその場合はother 13}catch(e){ 14 if(e instanceof ErrorAsync1){ 15 console.log('error1') 16 } 17 else if(e instanceof ErrorAsync2){ 18 console.log('error2') 19 }else{ 20 console.log('other') 21 } 22}

javascript

1Promise.resolve() 2 .then(()=>async1().catch(e=>throw new ErrorAsync1())) 3 .then(()=>async2().catch(e=>throw new ErrorAsync2())) 4 .then(()=>{ 5 console.log('success') 6 }) 7 .catch((e)=>{ 8 if(e instanceof ErrorAsync1){ 9 console.log('error1') 10 } 11 else if(e instanceof ErrorAsync2){ 12 console.log('error2') 13 }else{ 14 console.log('other') 15 } 16 }); 17

投稿2020/01/13 08:05

fijino

総合スコア136

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問