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

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

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

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

Q&A

解決済

2回答

14767閲覧

Javascript の 同期処理が上手くできない。

dwayne_johnson

総合スコア86

JavaScript

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

0グッド

5クリップ

投稿2018/06/15 13:53

かれこれ4時間ほど試行錯誤したが、全くわからず、困り果てています。

やりたいこと

現在地を取得して、その値を検索のクエリに入れたいです。

async getPosition() { // 現在地を取得 const lonlat = await navigator.geolocation.getCurrentPosition( // 取得成功した場合 function (position) { alert("緯度:" + position.coords.latitude + ",経度" + position.coords.longitude); const lon = position.coords.longitude const lat = position.coords.latitude const result = `lon=${lon}&lat=${lat}` console.log(result) // ここは正しく表示 return result }, // 取得失敗した場合 function (error) { switch (error.code) { case 1: //PERMISSION_DENIED alert("位置情報の利用が許可されていません"); break; case 2: //POSITION_UNAVAILABLE alert("現在位置が取得できませんでした"); break; case 3: //TIMEOUT alert("タイムアウトになりました"); break; default: alert("その他のエラー(エラーコード:" + error.code + ")"); break; } } ); return lonlat } async handleAreaChange(value) { this.setState({ selected_area: value }); let search_by = "" switch (value) { case "現在地": search_by = "location"; console.log("現在地") break; case "駅名": search_by = "station"; console.log("駅名") break; case "建物名": search_by = "name"; console.log("建物名") break; default: break; } const search_query = await this.getPosition(); console.log(search_query) // undefined になる fetch(`https://my-fucking-great-app/${search_by}?${search_query}`, { mode: 'cors', credentials: 'include', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' } }) .then(res => res.json()) .then( (result) => { this.setState({ data: result }); }, (error) => { this.setState({ data: error }); } ) } // いろんなとこにasync await 入れて試しまくったので、変な箇所があるかもしれません

自分の考えている挙動としては、const search_query = await this.getPosition();の箇所で、search_queryが生成されるのを待ち、それが取得されたら、fetchが行われるというものです。

しかし、どうがんばってもsearch_queryの値がundefinedになってしまいます。まだまだ非同期処理周りの知識がなく、解決できません。

どなたか解決法をご教授いただければ幸いです。

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

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

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

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

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

guest

回答2

0

ベストアンサー

navigator.geolocation.getCurrentPosition()はただのコールバック関数であり、Promise化された関数ではないですので、awaitをつけても完了を待ってくれるわけではありません。手動でPromise化する必要があります。

JavaScript

1 getPosition() { 2 return new Promise((resolve, reject) => { 3 // 現在地を取得 4 navigator.geolocation.getCurrentPosition( 5 // 取得成功した場合 6 (position) => { 7 alert("緯度:" + position.coords.latitude + ",経度" + position.coords.longitude); 8 const lon = position.coords.longitude; 9 const lat = position.coords.latitude; 10 const result = `lon=${lon}&lat=${lat}`; 11 console.log(result); // ここは正しく表示 12 resolve(result); 13 }, 14 // 取得失敗した場合 15 (error) => { 16 switch (error.code) { 17 case 1: //PERMISSION_DENIED 18 alert("位置情報の利用が許可されていません"); 19 break; 20 case 2: //POSITION_UNAVAILABLE 21 alert("現在位置が取得できませんでした"); 22 break; 23 case 3: //TIMEOUT 24 alert("タイムアウトになりました"); 25 break; 26 default: 27 alert("その他のエラー(エラーコード:" + error.code + ")"); 28 break; 29 } 30 reject(error.code); 31 } 32 ); 33 }); 34 }

注意点はいくつかあります。

  1. getPosition()asyncは付けません。Promiseを返す場合は通常の関数(メソッド)として作ります。
  2. 失敗はrejectしていますが、その場合はawiatでは例外発生になります。例外にしたくない場合は、適当な値をresolveで返してください。

投稿2018/06/15 22:01

raccy

総合スコア21735

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

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

dwayne_johnson

2018/06/16 00:33

ありがとうございました!!! getPosition で Promise を返すようにすることで、handelAreaChange内で this.getPosition を await させることができるようになり、それによりsearch_query は getPosition の完了をまって値が決まるようになりました。 いただいたコードのおかげで、Promise や async/await の挙動を学ぶきっかけにもなりました。ありがとうございました。
guest

0

Promise や async/await の挙動などを学ぶ時に参考にしたサイト

特に、

async function(asyncで宣言した関数)は何をするのか

async functionは呼び出されるとPromiseを返す。
async functionが値をreturnした場合、Promiseは戻り値をresolveする。
async functionが例外や何らかの値をthrowした場合はその値をrejectする。

awaitは何をするのか

awaitを指定した関数のPromiseの結果が返されるまで、async function内の処理を一時停止する。
結果が返されたらasync function内の処理を再開する。

以下、修正した後のコード

getPosition() { // 現在地を取得 return new Promise((resolve, reject) => { navigator.geolocation.getCurrentPosition( // 取得成功した場合 (position) => { alert("緯度:" + position.coords.latitude + ",経度" + position.coords.longitude); const lon = position.coords.longitude const lat = position.coords.latitude const result = `lon=${lon}&lat=${lat}` console.log(result) resolve(result); }, // 取得失敗した場合 (error) => { switch (error.code) { case 1: //PERMISSION_DENIED alert("位置情報の利用が許可されていません"); break; case 2: //POSITION_UNAVAILABLE alert("現在位置が取得できませんでした"); break; case 3: //TIMEOUT alert("タイムアウトになりました"); break; default: alert("その他のエラー(エラーコード:" + error.code + ")"); break; } console.log(error.code); reject(error.code); } ); }) } async handleAreaChange(value) { this.setState({ selected_area: value }); let search_by = "" let search_query = "" switch (value) { case "現在地": search_by = "location"; search_query = await this.getPosition(); console.log("現在地") break; case "駅名": search_by = "station"; console.log("駅名") break; case "建物名": search_by = "name"; console.log("建物名") break; default: break; } console.log(search_query) // 現在地の入ったsearch_queryが表示 // 以下省略

投稿2018/06/16 00:38

編集2018/06/16 01:22
dwayne_johnson

総合スコア86

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問