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

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

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

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

Ajax

Ajaxとは、Webブラウザ内で搭載されているJavaScriptのHTTP通信機能を使って非同期通信を利用し、インターフェイスの構築などを行う技術の総称です。XMLドキュメントを指定したURLから読み込み、画面描画やユーザの操作などと並行してサーバと非同期に通信するWebアプリケーションを実現することができます。

Q&A

解決済

2回答

2675閲覧

ループ中の非同期処理結果を一つの文字列にまとめて、thenで出力するには

TakahashiManabu

総合スコア11

JavaScript

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

Ajax

Ajaxとは、Webブラウザ内で搭載されているJavaScriptのHTTP通信機能を使って非同期通信を利用し、インターフェイスの構築などを行う技術の総称です。XMLドキュメントを指定したURLから読み込み、画面描画やユーザの操作などと並行してサーバと非同期に通信するWebアプリケーションを実現することができます。

0グッド

0クリップ

投稿2018/02/20 07:55

大変お世話になります。

現在、ajaxでPHPスクリプトに情報を流した後、
その結果をうけた内容を受け、画面に表示するというモデルを構築しています。
より厳密には、ajaxで送信するのはwordやpdfなどのドキュメントファイルで、ドラッグアンドドロップ→ajaxにてPHPへ渡す→結果の値(具体的には「○○○ファイルをアップロードしました」のような文言)を画面で表示するルートをだどりたいと思っています。

これだけであれば、問題なく上記のようなメッセージを出力させることができたのですが、
それに加えて、複数アップロードファイル数分のajax送信処理→結果受取の処理をしようとすると、
画面に出力される結果は不安定、つまり1つのファイル分の結果のみだったり、問題なく帰ってきたりと
結果がまちまちになってしまうのです。

非同期通信の性質から、非同期処理をスルーしてその先の処理を先行してしまうことがこうした結果を生むことがわかってきました。しかし、そうなると、安定してアップロードしたファイル数分の処理を行い、その結果を返し、それを画面に問題なく表示させるためには、どのような知恵が必要でしょうか?

ちなみに、下記にそのサンプルコードを示しますが、ajax処理結果を受けた後、.then以下のコールバック関数が、一つの変数に結果を回数分追加して代入していき、その変数を次のthenで出力ダイアログにセットする、という具合でスクリプトを進めるようにしております。

大変複雑なモデルを記述してしまうようで、恐縮に存じますが、何か良い知恵がございましたらご教示の程お願い申し上げます。

該当のソースコード

Javascript

1var dfd = $.Deferred(); 2 3 let promise = new Promise((resolve, reject)=>{ 4 5 for (var i = 0; i < files.length; i++){ 6 7 var fd = new FormData(); 8 var px = sendFileToServer(fd).then(function(result){ 9 10 message.push('<p>'+result+'</p>'); 11 m = message.join(''); 12 resolve(m); 13 14 }); 15 16 } 17 18 }) 19 .then(function(n){ 20 21 setTimeout(()=>{ 22 23 /**************************************** 24 完了ダイアログボックスの生成 $.confirm() 25 ****************************************/ 26 $.confirm({ 27 title: 'File Uploading Done', 28 content: '以下のファイルのアップロード結果<br>'+n, 29 type: 'blue', 30 typeAnimated: true, 31 buttons: { 32 OK: function () { 33 } 34 } 35 }); 36 },1000); 37 38 });

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

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

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

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

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

guest

回答2

0

sendFileToServer(fd)の戻り値はpromiseなんですか?
だったらpromiseの配列にしてしまって、Promise.allで受け取る手法が使えそうですね。

参照の切れた変数が大量にあり、
どうすれば動くのかさっぱり分かりませんが、大まかにはpromiseの配列を作って、
Promise.allで受け、thenで実行するようにすれば全てのファイルのアップロードの完了を待ってから処理を実行することが可能です。

JavaScript

1const sendFiles = files.map(file => { 2 // fileは何処で使うの?FormDataに入れてもダメそうだけど突っ込んでみました 3 const fd = new FormData(file); 4 return sendFileToServer(fd); 5}); 6Promise 7 .all(sendFiles) 8 .then(values => { 9 $.confirm({ 10 title: 'File Uploading Done', 11 content: '以下のファイルのアップロード結果<br>'+n, 12 type: 'blue', 13 typeAnimated: true, 14 buttons: { 15 OK: function () { 16 } 17 } 18 }); 19 });

投稿2018/02/20 08:15

miyabi-sun

総合スコア21158

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

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

TakahashiManabu

2018/02/20 15:29

コメント有難う御座います。返信が遅れまして申し訳ございません。 頂いたスクリプトは大変わかりやすく、当初miyabi-sunさまのもので実験をしておりました。 ところが、const sendFiles = files.map(file => {のところで、unexpected tokenというエラーメッセージがでてSyntax Errorが生じてしまいました。この点、何かごぞんでしょうか? 何度もお伺いして申し訳ございません。。。。
miyabi-sun

2018/02/20 16:42

うーん、サンプルで出したコードの部分はSyntax Errorは出てませんね。 前の行のカッコ閉じ忘れとかの可能性はありますね。 もし解決しないようでしたらコードを貼り付けてみて下さい。
TakahashiManabu

2018/02/21 02:15

miyabi-sunさま、本件ついて、良い報告と悪い報告です。。。 まず、良い報告から。原因が分かりました。 私の手違いで、const sendFiles = files.map(file => { のアローを->としてしまっていました。 これでsyntax Errorは生じなくなりました。 次に、悪い報告です。。。 実際にファイルをアップロードすると、エラーが生じ、 Uncaught TypeError: files.map is not a function.... とエラーメッセージが表示されます。。。。。
miyabi-sun

2018/02/21 02:44 編集

filesは正式な配列ではなかったのですね。 lengthついててfor文で回せるなら ```JavaScript let updateEvents = []; for (let i = 0; i < files.length; i++) {  const file = files[i];  const fd = new FormData(file);  updateEvents.push(sendFileToServer(fd)); } Promise.all(updateEvents) ``` こんな風に純粋な配列を用意してから詰め込んでやれば、 Promiseの配列になりますので、Promise.allに突っ込むことができます。 それと重ねて言いますが、質問文にあるfilesの実体も各種変数も宣言してるだけで使ってないものが多数あったりで、回答出来る状況じゃないです。 (きっと機密情報が多く含まれており、出せないのだろうと思います) なので私の回答も超ざっくりで適当にこんな感じとしか返せてないです。 この辺はうまいこと補いつつやってください。
guest

0

ベストアンサー

ファイルアップロードを非同期で処理しているのでしたら
わざわざpromiseしないでもアップロードが完了したものから
順次アップロード完了メッセージを表示していくほうが現実的では?
全部が終わるのをまって表示する意図がよくわかりません(もしそうなら)

sample

javascript

1$(function(){ 2 var d1 = $.Deferred(); 3 var d2 = $.Deferred(); 4 var d3 = $.Deferred(); 5 $.ajax({・・・}).done(function(){d1.resolve()}); 6 $.ajax({・・・}).done(function(){d2.resolve()}); 7 $.ajax({・・・}).done(function(){d3.resolve()}); 8 $.when( 9 d1,d2,d3 10 ).done(function(){ 11 console.log("end"); 12 }); 13});

sample2

複数のファイルをドラッグ・アンド・ドロップでバックグラウンドにアップロードし
すべてが終わったタイミングでアップロードしたファイル名を羅列

javascript

1$(function() { 2 $("#droppable").on({ 3 "dragenter dragover":function(e){ 4 e.preventDefault(); 5 return false; 6 }, 7 "drop":function(e){ 8 e.preventDefault(); 9 $('#view').text(""); 10 var ret=""; 11 var defs=[]; 12 var files = e.originalEvent.dataTransfer.files; 13 $.each(files,function(index,file){ 14 var fr = new FileReader(); 15 var def=$.Deferred(); 16 fr.addEventListener("load", function(e){ 17 var fd = new FormData(); 18 fd.append("myfile", new Blob([e.target.result],{"type":file.type}),file.name ); 19 /*recv.phpに対してmyfileというキーでファイルをアップロード*/ 20 $.ajax({ 21 "url":"recv.php", 22 "type":"post", 23 "data":fd, 24 "cache":false, 25 "processData": false, 26 "contentType": false, 27 }).done(function(data){ 28 ret+="<li>"+file.name+"</li>"; 29 return def.resolve(); 30 }); 31 }); 32 fr.readAsArrayBuffer(file); 33 defs.push(def.promise()); 34 }); 35 $.when.apply(null,defs).done(function(){ 36 $('#view').html("以下アップロードしました<ul>"+ret+"</ul>"); 37 }); 38 return false; 39 }, 40 }); 41});

HTML

1<div id="droppable" style="border: gray solid 1em; padding: 2em;"> 2ファイルをドロップしてください。 3</div> 4<div id="view"></div>

投稿2018/02/20 08:05

編集2018/02/20 11:31
yambejp

総合スコア114572

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

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

TakahashiManabu

2018/02/20 08:48

コメントありがとうございます。 確かに、完了ごとにメッセージを表示するのが一番わかりやすいのですが、アップしたファイルの数が多ければ、それだけ完了ダイアログの出現とクローズというタスクをユーザーがやらなければならなくなってしまうのです…… 理想的には、アップしたファイルの処理結果が一覧となって出てくるというのが、ウチのユーザーの要望でした… とまれ、コメントいただきありがとうございます!
yambejp

2018/02/20 11:32 編集

$.whenを利用したファイルアップロードの非同期処理をsample2に 書いておきました
yambejp

2018/02/20 11:49

ちなみに一つ一つのファイルに別のキーを与えてやったり myfile[]のようにしてformDataに一通りappendしてから $.ajaxは1度だけ呼べばよいような気もしますけどね
TakahashiManabu

2018/02/20 15:26

すごい!Sample2を活用させていただき、少々組み替えながら実行して、うまくいきました! どうやらdropイベントから続くfor文からドハマりしていたと思います。 ただ、いただいたスクリプト上で、 fd.append("myfile", new Blob([e.target.result],{"type":file.type}),file.name ); の部分がエラーになってしまいました。 というのも、実は、純粋なJSファイルで出力しているでのはなく、 全ての処理が完了後、Smartyテンプレートで画面を構築しているのです。 このとき、Smartyのレンダリング上でエラーと出てしまっていました。どうやら上記のスクリプト上でコロン「:」がSmartyのレギュレーションに引っかかってしまっていたようです。 ですが、そこについて取り急ぎコメントアウトしたところ、無事に望み通りの処理がなされました。 頂いたスクリプトの構成では、私が全然想定していなかったやり方なので(そもそもPHPはある程度てなれているものの、JSはさっぱり・・・)、きっちり理解して参りたいと思います。 取り急ぎ報告を申し上げます。(Smarty出力の条件をお伝えしておらず、大変申し訳ございません)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問