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

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

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

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

Q&A

解決済

2回答

641閲覧

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

olee46

総合スコア32

JavaScript

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

0グッド

1クリップ

投稿2018/04/17 16:22

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

Javascript

1ref.once('value') 2.then((snapshot) => { 3 if (!snapshot.child('done').exists()) { 4 throw 'notOnBreak'; 5 } else { 6 var r = snapshot.child('row-index').val(); 7 var c = snapshot.child('cell-index').val(); 8 var url = snapshot.child('photo-url').val(); 9 var promise; 10 // DB: add child 11 if (url == null) { // uses camera 12 promise = roomRef.child(peerId).set({'row-index': r, 'cell-index': c}) 13 .then(() => { 14 // SW: replace stream 15 sendStream(room, peerId); 16 // set style 17 mediaSetup(room, peerId); 18 setStyleOnJoin(peerId, 'yes'); 19 }); 20 } else { // no camera 21 promise = roomRef.child(peerId).set({'row-index': r, 'cell-index': c, 'photo-url': url}) 22 .then(() => { 23 // set style 24 setStyleOnJoin(peerId, 'no'); 25 }) 26 } 27 return promise; 28 } 29}).then(() => { 30 ref.remove(); 31})

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

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

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

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

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

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

guest

回答2

0

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

js

1(async () => { 2 3 const snapshot = await ref.once('value'); 4 5 if (!snapshot.child('done').exists()) { 6 throw 'notOnBreak'; 7 } 8 9 const rowIndex = snapshot.child('row-index').val(); 10 const cellIndex = snapshot.child('cell-index').val(); 11 const url = snapshot.child('photo-url').val(); 12 13 await roomRef.child(peerId).set({ 14 'row-index': rowIndex, 15 'cell-index': cellIndex, 16 ...url && { 'photo-url': url }, 17 }); 18 19 if (!url) { 20 sendStream(room, peerId); 21 mediaSetup(room, peerId); 22 setStyleOnJoin(peerId, 'yes'); 23 } else { 24 setStyleOnJoin(peerId, 'no'); 25 } 26 27 ref.remove(); 28 29})();

投稿2018/04/17 18:02

編集2018/04/18 02:36
mpyw

総合スコア5223

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

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

mpyw

2018/04/17 18:09

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

2018/04/17 21:28

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

2018/04/17 21:34

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

2018/04/18 02:38

...url && { 'photo-url': url } だと分かりにくいので ...(url && { 'photo-url': url }) って括ったほうが見やすいかも。これならわかります?
mpyw

2018/04/18 02:40

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

2018/04/18 02:47

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

0

ベストアンサー

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


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

JavaScript

1let r, c, url; 2ref.once('value').then((snapshot) => { 3 if (!snapshot.child('done').exists()) { 4 throw 'notOnBreak'; 5 } 6 r = snapshot.child('row-index').val(); 7 c = snapshot.child('cell-index').val(); 8 url = snapshot.child('photo-url').val(); 9 // DB: add child 10 const param = {'row-index': r, 'cell-index': c}; 11 url === null || param['photo-url'] = url; 12 return roomRef.child(peerId).set(param); 13}).then(() => { 14 if(url === null){ // uses camera 15 // SW: replace stream 16 sendStream(room, peerId); 17 // set style 18 mediaSetup(room, peerId); 19 setStyleOnJoin(peerId, 'yes'); 20 }else{ // no camera 21 // set style 22 setStyleOnJoin(peerId, 'no'); 23 } 24}).then(() => { 25 ref.remove(); 26});

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

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

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

投稿2018/04/17 17:45

defghi1977

総合スコア4756

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

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

olee46

2018/04/17 18:11

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問