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

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

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

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

Q&A

解決済

1回答

474閲覧

javascriptコードにおける想定外[実行順序][変数スコープ]

wwwww

総合スコア41

JavaScript

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

0グッド

0クリップ

投稿2021/01/18 13:18

編集2021/01/19 16:54

初歩的な質問にて、大変失礼いたします。
Javascriptコードを作成・nodeJsで実行しているのですが、挙動に想定外がありますため、以下伺わせてください。

javascriptコード

javascript

1(connection変数定義、connectは問題なく済み) 2 3var tempNum = 0; 4function countTheNum(){ 5 connection.query('SELECT count(*) as column1 FROM testTable', (err,rows) => { 6 if(err) throw err; 7 8 tempNum = rows[0].column1; 9 console.log("!"+tempNum); 10 return tempNum; 11 }); 12 connection.end(); 13 return tempNum; 14} 15 16console.log("!!"+countTheNum());

console

console

1!!0 2!18935

①実行順序

関数(countTheNum)を定義したのち、末尾で呼び出しているため、コンソール出力は

!18935 !!0

になるものと理解しているのですが、こうならないのはなぜなのでしょうか・・・?
(初心者につき、今今学習中なところですが、、汗
「非同期・同期関数」をうまく使えばできる、の認識は正ですか?)

②変数スコープ

末尾の

console.log("!!"+countTheNum());

においては、0ではなく、18935が適用されていてほしいです。
javascriptの変数スコープ周りを調べて、tempNumを関数外で宣言すれば良いもの、と理解していますが、解決できていません。
どのような書き方をすれば良いのでしょうか?

何卒よろしくお願いいたします。

[追記]修正後コード(期待した結果は未得)

javascript

1function sampleResolve() { 2 return new Promise(resolve => { 3 setTimeout(() => { 4 resolve( 5 connection.query('SELECT count(*) as column1 FROM table', (err,rows) => { 6 if(err) throw err; 7 tempNum = rows[0].column1; 8 console.log("!"+tempNum); 9 return tempNum; 10 }) 11 ); 12 connection.end(); 13 }, 4000); 14 }) 15} 16 17async function sample() { 18 const result = await sampleResolve(); 19 return result; 20} 21 22sample().then(result => { 23 console.log("!!"+result); 24});

[追記]修正後コードのコンソール

!![object Object] !18935

完成系(※参考)

(確実に冗長すぎる書き方なので、修正は必要な認識。ただ、やりたいことは実現できたので、一応記載した次第。)

javascript

1var tempNum; 2function sampleResolve(testMethod) { 3 return new Promise(resolve => { 4 setTimeout(() => { 5 connection.query('SELECT count(*) as column1 FROM table', (err,rows) => { 6 if(err) throw err; 7 tempNum = rows[0].column1; 8 console.log("!"+tempNum); 9 resolve(testMethod(tempNum)); 10 }) 11 connection.end(); 12 }, 4000); 13 }) 14} 15 16function testMethod(tempNum){ 17 console.log("call back"); 18 return tempNum; 19} 20 21async function sample() { 22 const result = await sampleResolve(testMethod); 23 return result; 24} 25 26sample().then(result => { 27 console.log("!!"+result); 28});

完成系のコンソール出力(※参考)

!18935 call back !!18935

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

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

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

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

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

hoshi-takanori

2021/01/18 13:39

「「非同期・同期関数」をうまく使えばできる」というか、connection.query はすでに非同期処理であり、書いた順番に実行されるはずという想定 (初心者にはよくある事ですが) が間違ってるだけですね。 connection.query('SELECT count(*) as column1 FROM testTable', (err,rows) => { の (err,rows) => { から対応する閉じかっこ } まではデータベースから結果が得られた後で呼ばれる無名関数なので、そのような結果になります。
wwwww

2021/01/19 13:37 編集

ご回答ありがとうございます!基礎が理解できておらずすいません。。 (週末に書籍買って一から勉強予定です) 他の方がご記載くださっているように、そこの処理を待つように書き換えれば良いもの、と認識の上、いろいろ試して理解を深めていきたいと思います!
hoshi-takanori

2021/01/19 14:17

待っては駄目です。待つんじゃなくて、結果が来たときに何をするかを記述するという考え方になります。
wwwww

2021/01/19 16:10

承知いたしました。 queryの閉じカッコ"}"の直前にて、コールバック関数を呼び出して、そこでresolveを記述すれば、同期的にかけるものと、現在理解しています。これから試してみます! ありがとうございます。
guest

回答1

0

ベストアンサー

こうならないのはなぜなのでしょうか・・・?

クエリの処理は非同期で行われますので、connection.queryに渡した関数の処理は、countTheNumの残りのコードより後に行われます。

0ではなく、18935が適用されていてほしいです。

無理です。connection.queryに渡した関数が実行される前にcountTheNumは終了してしまいますので、元からの値である0がそのままreturnされます。

投稿2021/01/18 13:39

maisumakun

総合スコア145186

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

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

maisumakun

2021/01/18 13:41

> どのような書き方をすれば良いのでしょうか? countTheNum自体がコールバックを受け取るようにする、あるいはPromiseを返すようにする(呼ぶ側もそれを前提に使う)必要があります。単なる数値を返す形で書くことはできません。
wwwww

2021/01/19 13:31

ありがとうございます! 申し訳ありませんが、追記コードまで書けたのですが、これで動作しないのは何故でしょうか…? 理解が鈍くすいません。。
maisumakun

2021/01/19 13:38

sampleResolveでresolve(connection.query(略))のようにしていますが、これでは「connection.queryの返り値で充足するPromise」を返すことになります。 クエリ終了時のコールバックでresolveを呼んでください。
wwwww

2021/01/19 16:11 編集

早速のご回答、ありがとうございます! >countTheNum自体がコールバックを受け取るようにする 「connection.query(〜=> {})」(の閉じカッコ直前?)にて、別途定義したコールバック関数を呼び、その中にresolveを書けば良いもの、と理解しました。今から試してみたいと思います! >(あるいは)Promiseを返すようにする(呼ぶ側もそれを前提に使う) 言及なくすいません、私はこちらで書いた自己認識でおります。「呼ぶ側」であるasync function sample内でよんでいるsampleResolveにawaitをつけることで、処理が受け取れるもの、と思っておりましたが、その上では何がよくないのでしょうか…。 (週末に本などで体系だった話として理解したいと思います… 何度もご返答を頂きありがとうございます…m(_ _)m )
wwwww

2021/01/19 16:56

ご回答・返答をいただいた方々、ありがとうございました。 実現したいことについては、一応解決しましたので、質問はクローズさせていただきました。 (callBack関数で非同期関数を同期的に扱っている理由、そもそももっと綺麗な書き方があるのではないか、などなど調べて理解することはありますが、諸々勉強になりました。)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問