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

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

ただいまの
回答率

90.51%

  • JavaScript

    16918questions

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

Promiseの分岐で、ネストを回避したい

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 326

olee46

score 23

以下のようなコードがあります。
thenの中で条件分岐があり、条件に応じて次に実行するPromiseが変わります。
Promise.allについて読んでみましたが、それが使えるのか/どう使えばいいのかわからず、
ネストになってしまいました。

ref.once('value')
.then((snapshot) => {
    if (!snapshot.child('done').exists()) {
        throw 'notOnBreak';
    } else {
        var r = snapshot.child('row-index').val();
        var c = snapshot.child('cell-index').val();
        var url = snapshot.child('photo-url').val();
        var promise;
        // DB: add child 
        if (url == null) { // uses camera
            promise = roomRef.child(peerId).set({'row-index': r, 'cell-index': c})
            .then(() => {
                // SW: replace stream
                sendStream(room, peerId);
                // set style
                mediaSetup(room, peerId);
                setStyleOnJoin(peerId, 'yes');
            });
        } else { // no camera
            promise = roomRef.child(peerId).set({'row-index': r, 'cell-index': c, 'photo-url': url})
            .then(() => {
                // set style
                setStyleOnJoin(peerId, 'no');
            })
        }
        return promise;
    }
}).then(() => {
    ref.remove();
})

このネストを回避する方法があれば教えてください。
よろしくお願いします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

+2

NOTE:
動作検証はしていませんので, コードの確からしさについては判断できかねます.


処理が途中で分岐している以上, Promiseのインデントとif文によるインデントは回避できないものとして, throw文におけるelse部の除去, 変数の定義場所や条件判定のタイミングをずらすことで二段程度はインデント(及びPromiseのネスト)を除去することが出来るでしょう.

let r, c, url;
ref.once('value').then((snapshot) => {
    if (!snapshot.child('done').exists()) {
        throw 'notOnBreak';
    }
    r = snapshot.child('row-index').val();
    c = snapshot.child('cell-index').val();
    url = snapshot.child('photo-url').val();
    // DB: add child 
    const param = {'row-index': r, 'cell-index': c};
    url === null || param['photo-url'] = url;
    return roomRef.child(peerId).set(param);
}).then(() => {
    if(url === null){ // uses camera
        // SW: replace stream
        sendStream(room, peerId);
        // set style
        mediaSetup(room, peerId);
        setStyleOnJoin(peerId, 'yes');
    }else{ // no camera
        // set style
        setStyleOnJoin(peerId, 'no');
    }
}).then(() => {
    ref.remove();
});


NOTE:
async-await構文を用いれば, 上記のPromiseによるインデントすら必要なくなります.(とは言え, 新たにtry-catchが必要となるので, 結果としてインデント量に変わりはありません.)

Promise.allについて読んでみましたが、それが使えるのか/どう使えばいいのかわからず、

今回のユースケースにおいてはPromise.allの使用は不適です.(本メソッドは単一の値を返すPromiseの配列を, 配列を返す単一のPromiseに変換します)

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/04/18 03:11

    ありがとうございます。urlをletにして外側に出せばthenの中でアクセスできるのが個人的にポイントでした。また、throwする場合にelseが不要なこともご指摘ありがとうございます。こちらのコードで実装してみましたが、問題なく動作しました。

    キャンセル

  • 2018/05/16 16:11 編集

    @defghi1977
    try...catch でネストが深くなるとのことですが await/catch パターンで解決します

    https://qiita.com/akameco/items/cc73afcdb5ac5d0774bc

    キャンセル

+2

既存のコードの中に catch メソッドの呼び出しが無いので async-await にしたからといって必要性が発生するわけではないですね。やっぱりこっちのほうが見やすくないでしょうか? (async-await 使ってるのでついでに Object Spread Operator も使います)

(async () => {

    const snapshot = await ref.once('value');

    if (!snapshot.child('done').exists()) {
        throw 'notOnBreak';
    }

    const rowIndex = snapshot.child('row-index').val();
    const cellIndex = snapshot.child('cell-index').val();
    const url = snapshot.child('photo-url').val();

    await roomRef.child(peerId).set({
        'row-index': rowIndex,
        'cell-index': cellIndex,
        ...url && { 'photo-url': url },
    });

    if (!url) {
        sendStream(room, peerId);
        mediaSetup(room, peerId);
        setStyleOnJoin(peerId, 'yes');
    } else {
        setStyleOnJoin(peerId, 'no');
    }

    ref.remove();

})();

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/04/18 03:09

    Promise は「解決がコールバック関数の中で行われる」という場合だけ必要で,それ以外は基本的に async-await だけ書いてればいいです。

    キャンセル

  • 2018/04/18 06:28

    async-awaitは初めて見たので、少し調べました。たしかに簡潔にかけますね!ありがとうございます

    キャンセル

  • 2018/04/18 06:34

    Object Spread Operatorのところがわかりませんでした。
    array = [1, 2, 3];
    foo(array[0], array[1], array[2]) と foo(...array)が同値であるのはわかったのですが、回答の中で...url && がどういう意味を持つのか、もしよろしければ補足をお願いします。

    キャンセル

  • 2018/04/18 11:38

    ...url && { 'photo-url': url }

    だと分かりにくいので

    ...(url && { 'photo-url': url })

    って括ったほうが見やすいかも。これならわかります?

    キャンセル

  • 2018/04/18 11:40

    {} リテラルの中で ... を使ったとき、それが iterable であれば key: value のペアを展開し,undefined や null であれば何もしない,という挙動になります

    キャンセル

  • 2018/04/18 11:47

    なるほど!わかりました、ありがとうございます!

    キャンセル

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

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

関連した質問

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

  • JavaScript

    16918questions

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