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

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

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

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Node.js

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

JavaScript

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

Q&A

解決済

1回答

8313閲覧

NodejsでPromise.allの.thenとその後の同期処理の実行順を保証したい

mao999

総合スコア111

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Node.js

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

JavaScript

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

0グッド

0クリップ

投稿2016/08/09 05:31

編集2016/08/09 14:41

Node.jsとmysqlモジュールでサーバサイドのプログラムを作成しています。

###やりたいこと
for文の中にMySQLの問い合わせ処理をいくつか書き、
その結果を用いて配列を作成したい。
※SQL問い合わせのそれぞれの結果レコードは必ず1件になります。
mysqlクライアントを用いてクエリを事前に確認しています。

###分かったこと
・MySQLの問い合わせ処理は、mysqlモジュールを使って非同期処理で行われる。
・for文の中で非同期処理をしたい場合、Promiseを使用して、for文の外で結果を取る。
・Promise.allの.thenでプロミス全てが完了した時に処理を行える。

###問題点

  • Promiseと即時処理/同期処理の実行順を保証できない

SQL文の結果を全て取得し終わってから配列を作成したいのに、
まだPromiseが完了していないのに最後のfor文が実行されてしまって、
SQLの結果が反映されない。
Promise.allと最後のfor文の間に、Promise.allが全て終わるまで待つようなブロッキングをする方法は無いのでしょうか。

  • 2次元配列が直感と違う

javascriptでは2次元配列をサポートしていないらしく、
var array = [[1,2],[3,4],[5,6]];var ar1 = array[0];var i = ar1[0];の様にアクセスすればそれらしい事は出来るみたいですが、
下記ソースコードPromise.all([promisesA]).then(~~内のresults.lengthsqlresults.lengthの値が逆なのではないか?
直感では、results.length=31と、SQLの結果sqlresults.length=1ですが、
console.logで出力するとresults.length=1sqlresults.length=31が返ってきます。
何故でしょうか。

宜しくお願い致します。

###ソースコード
少し長くなります。

lang

1//SQLでAValueを得るための処理 2var promisesA = []; 3var resultsA = []; 4function getA(arg){ 5 new Promise(function(resolve,reject){ 6 var query_sql = connection.query({ 7 sql : "~~~~", //略 8 timeout: 3000, 9 values : [~~~~] //略 10 },function(error,results,fields){ 11 if(error){ 12 reject(error,query_sql); 13 return; 14 } 15 resolve(results); 16 }); 17 }); 18} 19//SQLでBValueを得るための処理 20var promisesB = []; 21var resultsB = []; 22function getB(arg){ 23 new Promise(function(resolve,reject){ 24 var query_sql = connection.query({ 25 sql : "~~~~", //略 26 timeout: 3000, 27 values : [~~~~] //略 28 },function(error,results,fields){ 29 if(error){ 30 reject(error,query_sql); 31 return; 32 } 33 resolve(results); 34 }); 35 }); 36} 37//SQLでCValueを得るための処理 38var promisesC = []; 39var resultsC = []; 40function getC(arg){ 41 new Promise(function(resolve,reject){ 42 var query_sql = connection.query({ 43 sql : "~~~~", //略 44 timeout: 3000, 45 values : [~~~~] //略 46 },function(error,results,fields){ 47 if(error){ 48 reject(error,query_sql); 49 return; 50 } 51 resolve(results); 52 }); 53 }); 54} 55for(var i=0; i < 31; i++){ 56 promisesA.push(getA(~~~)); 57 promisesB.push(getB(~~~)); 58} 59Promise.all([promisesA]) 60 .then(function(results){ 61 for(var i=0; i < results.length; i++){ 62 var sqlresults = results[i]; 63 resultsA.push(sqlresults[0].AValue); 64 if(sqlresults[0].AValue > 0){ 65 promisesC.push(getC(~~~)); 66 } 67 } 68 }) 69 .catch(function(error,query){ 70 }); 71Promise.all([promisesB]) 72 .then(function(results){ 73 for(var i=0; i < results.length; i++){ 74 var sqlresults = results[i]; 75 resultsB.push(sqlresults[0].BValue); 76 } 77 }) 78 .catch(function(error,query){ 79 }); 80Promise.all([promisesC]) 81 .then(function(results){ 82 for(var i=0; i < results.length; i++){ 83 var sqlresults = results[i]; 84 resultsC.push(sqlresults[0].CValue); 85 } 86 }) 87 .catch(function(error,query){ 88 }); 89//SQL問い合わせの結果をもとに配列を作成 90for(var i=0; i < 31; i++){ 91 //配列作成 92}

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

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

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

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

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

guest

回答1

0

ベストアンサー

見直すべき点はあるような気はしますが、ご参考までにとりあえず思いついた回答を。
Node.js 4.4.3です。
Promisesは見当たらなかったのでPromiseにしてます。あと getX は returnするようにしています。

配列どうこうは、allに配列(そもそもpromisesAが配列なのに更に配列にしている)渡しているからじゃないでしょうか。
それを除けば、こう渡せば当然こうとれるという私の感覚とは反してませんでした。

Promiseの結果をとりたいならthenでやるべきでしょう。ということで変更したところ:

  • Promises.all([promisesA])Promise.all(promisesA)という形に変えています。
  • A->C->B-> 結果 にしています。(なのでAとBは同時には走りません)
  • SQLの実行はsetTimeoutに変えています。

Promiseの終わりでPromiseを返し、結果修正のところまでthenでつないでいます。
setTimeoutでresolveしているのをその後のPromiseで利用する形に合わせてますので、thenの中はあまり変えてないつもりです。

js

1//SQLでAValueを得るための処理 2var promisesA = []; 3var resultsA = []; 4function getA(arg){ 5 var v = arg; 6 return new Promise(function(resolve,reject){ 7 setTimeout(function(){ 8 resolve([{AValue: (arg + 1) * 100 + arg}]); 9 }, 100); 10 }); 11} 12//SQLでBValueを得るための処理 13var promisesB = []; 14var resultsB = []; 15function getB(arg){ 16 return new Promise(function(resolve,reject){ 17 setTimeout(function(){ 18 resolve([{BValue: 'B:' + arg}]); 19 }, 400); 20 }); 21} 22//SQLでCValueを得るための処理 23var promisesC = []; 24var resultsC = []; 25function getC(arg){ 26 return new Promise(function(resolve,reject){ 27 setTimeout(function(){ 28 resolve([{CValue: 'C:' + arg}]); 29 }, 50); 30 }); 31} 32for(var i=0; i < 31; i++){ 33 promisesA.push(getA(i)); 34 promisesB.push(getB(i)); 35} 36 37Promise.all(promisesA) 38 .then(function(results){ 39 // A 40 for(var i=0; i < results.length; i++){ 41 var sqlresults = results[i]; 42 resultsA.push(sqlresults[0].AValue); 43 if(sqlresults[0].AValue > 0){ 44 promisesC.push(getC(sqlresults[0].AValue)); 45 } 46 } 47 return Promise.all(promisesC); 48 }) 49 .then(function(results){ 50 // C 51 for(var i=0; i < results.length; i++){ 52 var sqlresults = results[i]; 53 resultsC.push(sqlresults[0].CValue); 54 } 55 56 return Promise.all(promisesB); 57 }) 58 .then(function(results){ 59 // B 60 for(var i=0; i < results.length; i++){ 61 var sqlresults = results[i]; 62 resultsB.push(sqlresults[0].BValue); 63 } 64 }) 65 .then(function(results){ 66 for(var i=0; i< 31; i++){ 67 console.log(resultsA[i]); 68 console.log(resultsB[i]); 69 console.log(resultsC[i]); 70 } 71 }) 72 .catch(function(error,query){ 73 });

投稿2016/08/09 11:37

flied_onion

総合スコア2604

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

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

mao999

2016/08/09 14:24 編集

ご回答有難うございます! Node.jsのバージョンはv6.3.1でした。 PromisesはPromiseの間違いでした。修正しておきます。 仰るとおり、見なおすべき点は色々あるはずです。 javascriptで書くのは初めてなので、非同期処理をする時の定石/ベストプラクティスの様なものはまだ殆ど知りません。 配列の件、確かに仰る通りです。 こう渡せば、こう取れますよね。 うっかり見逃していました。 ソースコード書いて頂いて有難うございます。 後で確認しますので、またコメントします。
mao999

2016/08/09 16:36

・getXでreturnする ・Promises.all([promisesA]) は Promise.all(promisesA)に修正 ・Promiseの終わりでPromiseをreturnし、結果修正のところまでthenでつなぐ の変更を加えた結果、 所望の動作をさせる事が出来ました。 有難うございました。
flied_onion

2016/08/09 16:52

動いたようで良かったです。 Promiseは同期処理との区分けがなかなか難しいですが頑張ってください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問