🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
MySQL

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

Node.js

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

Express

ExpressはNode.jsのWebアプリケーションフレームワークです。 マルチページを構築するための機能セットおよびハイブリッドのWebアプリケーションを提供します。

Q&A

解決済

1回答

1542閲覧

Node.jsのExpress+MySQLの取得データが消える

HYDESA

総合スコア8

MySQL

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

Node.js

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

Express

ExpressはNode.jsのWebアプリケーションフレームワークです。 マルチページを構築するための機能セットおよびハイブリッドのWebアプリケーションを提供します。

0グッド

0クリップ

投稿2021/01/05 08:02

編集2021/01/05 08:28

お世話になります。
自分自身がnode.jsの根本的なことをわかっていないかも知れません。

app.getで取得したデータですが、connection.queryから外れてしまうと後で使えなくなってしまうので、変数に代入しましたが、やはり消えてしまいます。

javascript

1// 前略 2var cnt = 0; 3app.get('/',( request, response ) => { 4 connection.query("select count(*) as count from test", function(err,result){ 5 if(err) throw err; 6 cnt = result[0].count; // 出力は2とする 7 } 8 console.log(cnt); // 結果0 9}); 10// 後略

この場合、どうすれば変数にデータが残せるでしょうか。
よろしくお願い致します。

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

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

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

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

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

guest

回答1

0

ベストアンサー

Node.js名物の非同期処理ですね。
そういう順番で動作をするのが仕様です。
「イベントループ」という名称で勉強出来るので、しっかり仕様をおさえましょう。

そもそもなんだってそんな動きになるのか?という話ですが、
これはNode.jsの元ネタになったJavaScript(以下JS)の目的や用途にも関わる話です。

JSはブラウザ上で画面を動的に操作する
DHTMLとして作られた言語です。
Webページの画面上には無数のテキストや要素、スクロール、ボタン等の要素があり、
それにフックさせまくって待つとなると莫大なコストが必要になります。

そこで、JSはイベント駆動という考え方を導入しました。
「イベント置き場」というものがあり、そこに「達成条件」と「実行してほしい処理(関数)」をセットで登録します。
ブラウザ上でマウスカーソルが動いた時、ボタンをクリックした時、無数の動作を逐一報告させ、
それがイベント登録した達成条件に合致した時、セットの関数を取り出して実行する。
こういう仕組みで非同期処理を実現させました。


js

1 connection.query("select count(*) as count from test", function(err,result){ 2 if(err) throw err; 3 cnt = result[0].count; // 出力は2とする 4 } 5 console.log(cnt); // 結果0

ここの部分に戻りましょう。
connection.query関数を実行する時に、
第一引数はSQL文のString型、第二引数は関数を指定しています。

Node.jsはJSと違ってWeb画面を表示して待つ事は無いけれど、
WebサーバでHTTPリクエストを待ったり、MySQLからの結果を待ったり、HDDからファイルの読み完了を待ったり
ブラウザとは次元が違うレベルで待ち散らかしてます。

その遅延実行を実現する為に、
第二引数の関数はその場では実行せず、
イベント置き場にイベント登録だけ行い、すぐに終了させています。

コードを全て実行してNode.jsの動作が全て完了した後に、
イベント待ちのタスクがあれば、イベントループという待機状態になります。
Node.jsはイベントの一覧を眺めて、イベント達成が行われていないかと巡回し始めます。

なので、下記のように「0秒待つ」というイベントを登録したとしても、
今動作させているコードが絶対先に実行されます。

js

1setTimeout( 2 function(){ console.log("a") }, 3 0 4); 5console.log("b"); 6// 実行結果は b => a の順

質問に戻りましょう。

この場合、どうすれば変数にデータが残せるでしょうか。

よろしくお願い致します。

残ってますよ。
2度目のアクセスのときにはconsole.log(cnt)の値は要望通りの値になっているはずです。

cntを2度目以降のキャッシュとして書くと
下記のような感じになります。

js

1var cnt = null; 2app.get('/',( request, response ) => { 3 // 真っ先にキャッシュを確認し、存在しているならSQL発行を行わず逃げる 4 if (cnt != null) { 5 response.end(cnt); 6 return; 7 } 8 // 私はこういう逃がす処理を書く時は1行で済ませる事が多い 9 // if (cnt != null) return response.end(cnt); 10 11 connection.query("select count(*) as count from test", function(err,result){ 12 if(err) throw err; 13 cnt = result[0].count; // 出力は2とする 14 // この関数内でやりたいことは全て書くしかない 15 response.end(cnt); 16 } 17}); 18// 後略

上記の「この関数内でやりたいことは全て書くしかない」は相当なネックで、
for文やif文の分岐を書く事が非常に難しくなります。

例えば3件のSQL発行を書くとなれば、コールバックが3回、関数宣言も3個で
コードのネストも3個分になるでしょう。
これを「コールバック地獄」と呼び、様々な技術者がこの問題に立ち向かい、ノウハウも探せば色々と出てきます。

このコールバック地獄は本件とは関係ありませんので、
とりあえず今回の質問を片付けてから、改めて勉強していってください。

投稿2021/01/05 09:39

miyabi-sun

総合スコア21203

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

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

HYDESA

2021/01/06 00:08

丁寧なご回答をありがとうございました。 欲しい情報を記載くださったので、大変助かりました。 しっかりと勉強します。
HYDESA

2021/01/06 01:41

追伸 console.logの表示タイミングから、非同期処理の意味がやっとわかりました。 非同期処理でFIFOだから、コールバック地獄の意味もわかりました。 大変勉強になりました。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問