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/06 00:08
2021/01/06 01:41