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

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

ただいまの
回答率

90.47%

  • JavaScript

    20935questions

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

  • Node.js

    2420questions

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

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

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 204

murabito

score 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
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+2

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

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))

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

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

async1()
    .catch(error => console.error('catch1:', error))
    .then(result => {
        console.log('then1:', result)
        return async2()
    })
    .catch(error => console.error('catch2:', error))
    .then(result => console.log('then2:', result))

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/02/18 21:56

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

    キャンセル

  • 2019/02/19 21:46

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

    キャンセル

0

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

Re: murabito さん

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/02/17 17:05

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

    キャンセル

  • 2019/02/17 17:07

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

    キャンセル

  • 2019/02/17 17:22

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

    キャンセル

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

  • ただいまの回答率 90.47%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • JavaScript

    20935questions

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

  • Node.js

    2420questions

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