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

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

ただいまの
回答率

91.45%

  • JavaScript

    10889questions

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

  • Node.js

    1175questions

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

  • 同期

    22questions

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

node.js 同期処理について

解決済

回答 1

投稿 2017/09/12 18:19 ・編集 2017/09/12 20:21

  • 評価
  • クリップ 1
  • VIEW 114

BECK_

score 54

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

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

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

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

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

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

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

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

var express         = require('express');
var app             = express();
const db            = require('mysql2');
const connection    = db.createConnection({
    host     : 'localhost',
    user     : 'hoge',
    password : 'fuga',
    database : 'hogedb'
});
var data  = [];

app.get('/aaa/bbb', function (req, res) {

     //1.データ取得・編集処理
    connection.query("SELECT * FROM main_tbl", function(e1, r1, f1) {

        data = r1;
        for(i = 0 ; i < r1.length ; i++) {

            console.log('info_1');

            connection.query("SELECT * FROM sub_tbl WHERE id = ?", r1[i].id, function(e2 , r2 ,f2) {

                console.log('info_2');

                for(x = 0 ; x < r2.length ; x++) {
                    //サブテーブルを元に処理を行いdataの該当要素に追加する
                }
            });

            console.log('info_3');

        }
    });

        //2.処理結果出力
    res.set('application','json');
    res.set('Access-Control-Allow-Origin','*');
    res.set('Access-Control-Allow-Headers','Origin, X-Requested-With, Content-Type, Accept');
    res.send({'data': data, 'status': 'success'});
});

var server = app.listen(8080, function () {
  var host = server.address().address;
  var port = server.address().port;
  console.log('listening at http://%s:%s', host, port);
});

追記

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

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

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

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

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

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

投稿 2017/09/13 19:14

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/09/13 23:03 編集

    so87さん、回答頂き有難う御座います。
    なるほどやはり処理順序を保証するにはPromiseパターンが一般的なのですね。
    Promiseは再帰的なスタック処理を書かないといけない感じでしょうか..?
    いささか知恵熱気味ですw

    >"info_2"のほうのコールバック側にすべて完了したか判定させるロジックを仕込んで、コールバック完了時にレスポンス出力処理実行・・・とか

    確かに初期実装は簡単そうですが、フロー制御を都度コーディングするのは何となくダサい気がしますので頑張ってPromiseパターンを理解して実装してみようと思います。

    でも、ここら辺は言語仕様もしくはフレームワーク側でもいいので抽象化してて欲しかったりしますね。

    キャンセル

  • 2017/09/13 23: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というライブラリを使ったほうが書きやすい場面も多々…

    キャンセル

  • 2017/09/14 18:29

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

    キャンセル

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

ただいまの回答率

91.45%

関連した質問

  • 受付中

    EJS Expressを用いたテンプレートを用いた、サーバー側ファイルの取り扱い方について  

    Node.jsを用い、サーバー側にPDFファイル(sample.pdf)を格納しております。 クライアント側からの接続により、このファイルにアクセスする場合には、どのようにリンク

  • 解決済

    node.jsのmodule.exportsで循環参照

    あるwebアプリを作っててそこではexpressとsocketioを使用しています。 expressのインスタンスの処理等とルーティングを分けようと思って app.js

  • 解決済

    Javascriptで変数を参照できない

    お世話になっております。 表題の通り、関数の中で変数を上書きし、関数外でreturnをすると 関数の呼び出し元でundefinedとなってしまいます。 --- 省略 --

  • 解決済

    docker-composeでのPostgreSQL接続

    前提・実現したいこと dockerの練習として、docker-composeでpostgresqlを扱おうとしています。 発生している問題・エラーメッセージ 0 info

  • 解決済

    Node.jsのソースコード整理について

    Node.jsバージョン:6.9.1 Socket.IOバージョン:1.5.1 Node.js初心者です。Socket.IOを使ってチャットアプリケーションを制作しています

  • 解決済

    四則演算の結果を返すプログラム

    四則演算の結果を返すプログラムを作成する課題を与えられています。 ※結果をcurlコマンドで確認したいためjavascriptなどは使用できません。 以下のようにアクセスす

  • 解決済

    EC2上でのシンタックスエラーについて

    EC2にSSH接続して、Node.jsを起動するために「sudo npm start」のコマンドを走らせると下記のようなエラーが出てしまい原因がわからず困っています。 間違えって

  • 解決済

    JavascriptでQueryを呼び出すには

    手さぐりでMysqlを勉強しているのですが、Node.js内でクエリを実行するにはどうすればいいのでしょうか・・ 調べてはみたのですが、人によってはmudule.export

同じタグがついた質問を見る

  • JavaScript

    10889questions

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

  • Node.js

    1175questions

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

  • 同期

    22questions

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