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

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

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

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

JavaScript

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

同期

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

Q&A

解決済

1回答

407閲覧

node.js 同期処理について

BECK_

総合スコア94

Node.js

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

JavaScript

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

同期

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

0グッド

1クリップ

投稿2017/09/12 09:19

編集2017/09/12 11:21

javascriptの非同期処理に関して質問があります。

node.jsにて簡単なDBからの参照処理を書いていて非同期処理で挙動が思う通りに行かずに混乱してます。
やりたい事は親テーブルのレコードセットに対して、子テーブルから該当するキーのサブレコードを取得しJSON形式で返却したいのですが、
テーブルJOINの一発で取得出来なく、親レコードをfetchしながら逐次処理を考えています。

外側のqueryを発行しcallback関数がコールされるところまではOKですが、内側のクエリー発行のcallbackが実行される前に
後続ステップが実行されてしまってます。
それに関しては現在promiseと格闘中です..(汗

そこで挙動的に解せないのが大きな下記処理ブロック

1.データ取得・編集処理
2.処理結果出力

のシーケンスが順次処理されている事です。

非同期からすると、1のデータ処理完了を待たなく2.のレスポンス処理が実行されそうですが、そこは順次実行されていそうです。。
レスポンス処理の記述はこれで正しいのでしょうか?

とんちんかんな質問かもしれませんが宜しくお願いします。

JS

1var express = require('express'); 2var app = express(); 3const db = require('mysql2'); 4const connection = db.createConnection({ 5 host : 'localhost', 6 user : 'hoge', 7 password : 'fuga', 8 database : 'hogedb' 9}); 10var data = []; 11 12app.get('/aaa/bbb', function (req, res) { 13 14 //1.データ取得・編集処理 15 connection.query("SELECT * FROM main_tbl", function(e1, r1, f1) { 16 17 data = r1; 18 for(i = 0 ; i < r1.length ; i++) { 19 20 console.log('info_1'); 21 22 connection.query("SELECT * FROM sub_tbl WHERE id = ?", r1[i].id, function(e2 , r2 ,f2) { 23 24 console.log('info_2'); 25 26 for(x = 0 ; x < r2.length ; x++) { 27 //サブテーブルを元に処理を行いdataの該当要素に追加する 28 } 29 }); 30 31 console.log('info_3'); 32 33 } 34 }); 35 36 //2.処理結果出力 37 res.set('application','json'); 38 res.set('Access-Control-Allow-Origin','*'); 39 res.set('Access-Control-Allow-Headers','Origin, X-Requested-With, Content-Type, Accept'); 40 res.send({'data': data, 'status': 'success'}); 41}); 42 43var server = app.listen(8080, function () { 44 var host = server.address().address; 45 var port = server.address().port; 46 console.log('listening at http://%s:%s', host, port); 47});

追記

初回のリクエストは正常なレスポンスデータではなかったです。
data変数のスコープがグローバルだったため、2回目以降は正常に動作している様に振舞っていただけでした。。(汗
失礼しました。

この様な処理の場合、処理の先行、後続関係をどの様に制御したらよいのでしょうか?

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

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

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

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

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

guest

回答1

0

ベストアンサー

すべてのコールバック処理(SQL結果)が完了してからレスポンスを出力する必要がありますので、
Promiseパターンなしに実装するのは危険です。

もしPromiseパターンを使わないのなら、
コールバック数をカウントしておき、コールバック処理に完了カウンタを仕込み、データを溜め込んでいく、setIntervalで定期的にカウンタをチェック、コールバック数と同数になったらタイマー解除、溜め込んだデータを出力開始・・・とか

setIntervalだと応答速度がちょっと悪そうなので
"info_2"のほうのコールバック側にすべて完了したか判定させるロジックを仕込んで、コールバック完了時にレスポンス出力処理実行・・・とか
エラー処理含め、複雑な処理が追加された場合、メンテがどんどん苦しくなります。

ということで、やはりまずはPromiseパターン習得を優先すべきだと思います。
私はDB周りはPromiseでラッピングしまくったライブラリを自作して運用しております。
準備さえ整えば、同期処理のように書けるので頑張ってください。

投稿2017/09/13 10:14

so87

総合スコア764

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

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

BECK_

2017/09/13 14:03 編集

so87さん、回答頂き有難う御座います。 なるほどやはり処理順序を保証するにはPromiseパターンが一般的なのですね。 Promiseは再帰的なスタック処理を書かないといけない感じでしょうか..? いささか知恵熱気味ですw >"info_2"のほうのコールバック側にすべて完了したか判定させるロジックを仕込んで、コールバック完了時にレスポンス出力処理実行・・・とか 確かに初期実装は簡単そうですが、フロー制御を都度コーディングするのは何となくダサい気がしますので頑張ってPromiseパターンを理解して実装してみようと思います。 でも、ここら辺は言語仕様もしくはフレームワーク側でもいいので抽象化してて欲しかったりしますね。
so87

2017/09/13 14:42

Nodeのバージョンが8以上ならば、Promise化を助けてくれるutil.promisifyというユーティリティがあります。 http://yosuke-furukawa.hatenablog.com/entry/2017/05/10/101752 util.promisifyがない場合はbluebirdというPromise互換ライブラリに似たユーティリティがあります。 https://www.key-p.com/blog/staff/archives/104921 ちょっとだけ補助になります。ちょっとだけですがね^^ 言語的にはPromise自体が非同期処理を抽象化したオブジェクトで、 さらにasync/awaitによってかなり書きやすくなっておりますよ。 async/awaitは並列処理は苦手でcoというライブラリを使ったほうが書きやすい場面も多々…
BECK_

2017/09/14 09:29

so87さん、有難う御座います!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問