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

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

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

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

同期

複数のディレクトリに存在するファイルを更新した場合に、すべてのファイルにも更新が行われる事、又は、同じ記憶領域に同時にアクセスして内容の整合性が失われてしまう事をを防ぐ制御などを同期と呼びます。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

Q&A

解決済

3回答

427閲覧

Promiseで処理の実行順を保証したい

退会済みユーザー

退会済みユーザー

総合スコア0

JavaScript

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

同期

複数のディレクトリに存在するファイルを更新した場合に、すべてのファイルにも更新が行われる事、又は、同じ記憶領域に同時にアクセスして内容の整合性が失われてしまう事をを防ぐ制御などを同期と呼びます。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

0グッド

0クリップ

投稿2018/05/18 09:42

編集2018/05/18 09:51

前提・実現したいこと

クラスのプロパティに設定された複数の画像(base64文字列を格納した配列)を順にアップロードし、アップロードできた画像のパスをクラスのプロパティに設定し直したいです。

その後(画像がすべてアップロードされた後に)、クラスのプロパティをデータベースに保存したいのですが、その前段階でつまづいてます。
原因はわかっていますが、その解決方法がわかりません。

reduceを使っているからいけないのでしょうか。JS初心者なのでお手柔らかにご教示いただけると助かります。

発生している問題・エラーメッセージ

原因はアップロードが完了する(画像パスが設定される)前に、データベースに保存しにいっていることです。
以下画像の通り、アップロード完了時のログ(fuga)より前に、データベース保存時のログ(piyo )出力されており、画像がundefinedのままデータを保存しにいっていることがわかります。
※以下は2ファイルをアップロードした結果です
イメージ説明

該当のソースコード

save(data: Product): Promise<any> { return this.upload(data.images).then(images => { console.log(images); // 1. undefind data.images = images; // ここでプロパティを設定し直したい return data; }).then((data: Product) => { console.log("piyo"); // 2. piyo this.firestore.doc<Product>(`products/${id}`).update(data); // 3. error }).catch(err => { console.log('upload failed', err); }); } upload(images: string[]): Promise<string[]> { return images.reduce((promise: Promise<any>, image: string) => { return promise.then((uploadedImages) => { const path = `${new Date().getTime()}`; this.storage.ref(path).putString(image, 'data_url').then(snapshot => { console.log("fuga"); // 4. fuga uploadedImages.push(path); return uploadedImages; }); }); }, Promise.resolve([])); }

補足情報(FW/ツールのバージョンなど)

ストレージはFirebaseを使用しています。

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

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

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

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

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

guest

回答3

0

ベストアンサー

return promise.then((uploadedImages) => {で始まる関数に返り値がないため、この中で生成されたPromiseは、終了を待たれず放置されることになってしまいます。

ここから書き換えてもいいのですが、「大量のPromiseを全部待たせる」Promise.allという関数があるので、それを使ったほうがいいでしょう。

upload(images: string[]): Promise<string[]> { return Promise.all(images.map(image => { const path = `${new Date().getTime()}`; return this.storage.ref(path).putString(image, 'data_url').then(() => path); })) }

投稿2018/05/18 09:50

編集2018/05/18 09:52
maisumakun

総合スコア145183

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

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

退会済みユーザー

退会済みユーザー

2018/05/21 05:34

> 返り値がないため、この中で生成されたPromiseは、終了を待たれず放置されることになってしまいます。 確かに返り値がありませんでしたね。 ただ返り値があったらreduceでもPromise.allのように終了を待たせることができるのでしょうか? 今回のように「複数の子処理の終了を待たせる」いという状況においてはPromise.allという選択肢しかなかったのかというところが気になりました。 理解が追いついてなくてすみません。 > 「大量のPromiseを全部待たせる」Promise.allという関数があるので、それを使ったほうがいいでしょう。 勉強になります、ありがとうございます!
maisumakun

2018/05/21 05:45 編集

はい、Promise.prototype.thenのコールバック関数がPromiseを返した場合、.thenの返り値は「コールバックが返したPromiseも待つ」という挙動になります。 https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/then なお、reduceでつないでいくと、必然的に「1つのPromiseが終わってから次のPromiseを開始する」というような挙動になります。画像アップロードを並列してやりたいのであれば、Promise.allが適切、ということになります。
退会済みユーザー

退会済みユーザー

2018/05/21 05:50

大変勉強になりました、ありがとうございます!
guest

0

果たして、非同期処理にしなければならないんでしょうか。
Promise使わずに順番に実行していけばいいんじゃ

投稿2018/05/18 12:45

y_waiwai

総合スコア87749

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

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

0

bluebird の Promise.map もオススメ。
並列処理する数を簡単に制限できるので色んな場面で役立ちます。
なによりネイティブ実装の Promise より処理速い。

Promise.map | bluebird

javascript

1const Promise = require('bluebird'); 2 3upload(images: string[]): Promise<string[]> { 4 return Promise.map( 5 images, 6 (image: string) => { 7 const path = `${new Date().getTime()}`; 8 9 return this.storage 10 .ref(path) 11 .putString(image, 'data_url') 12 .then(() => path); 13 }, 14 { concurrency: 5 } // 並列処理の上限設定 15 ); 16}

投稿2018/05/18 12:43

yhg

総合スコア2161

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

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

退会済みユーザー

退会済みユーザー

2018/05/21 05:27

ありがとうございます!参考にさせていただきます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問