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

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

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

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

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

解決済

1回答

4758閲覧

javascriptの非同期処理が待ってくれません。

teradas

総合スコア1

JavaScript

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

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

9クリップ

投稿2022/01/27 23:35

DetaiDashboard3.js、DetailDashboardList.js、api.jsがあります。
コードは以下のとおりです。

DetaiDashboard3.js

Javascript

1 2const DetailDashboard3 = () => { 3 const [kuchikomis, setKuchikomis] = useState([]); 4 5 useEffect(() => { 6 fetch(); 7 }, []) 8 9 const preid = useParams(); 10 const stringprename = JSON.stringify(preid); 11 const obj = JSON.parse(stringprename); 12 13 const fetch = async() => { 14 const id = obj.id; 15 const data = await Api.openDetailDashboard(id); 16 console.log(data[0]); //1 17 await setKuchikomis(data); 18 console.log(data[0]); //2 19 console.log(kuchikomis); //3 20 } 21 const classes = useStyles(); 22 return ( 23 <div className={classes.root}> 24 <h1>詳細ページ</h1> 25 <DetailDashboardList kuchikomis={kuchikomis} fetch={fetch} /> 26 </div> 27 ) 28}; 29 30export default DetailDashboard3;

DetailDashboardList.js

Javascript

1const DetailDashboardList = (props) => { 2 const classes = useStyles(); 3 const kuchikomilist = props.kuchikomis.map((kuchikomi) => { 4 return ( 5 <ListItem key={kuchikomi.id}> 6 <h1>kuchikomilistの内容</h1> 7 省略 8 </ListItem> 9 ) 10 } 11 ); 12 return ( 13 <div className={classes.root}> 14 <h2>最近の投稿</h2> 15 <ul className={classes.ul}>{kuchikomilist}</ul> 16 </div> 17 ) 18} 19export default DetailDashboardList;

api.js

Javascript

1export const openDetailDashboard = async(id) => { 2 const kuchikomi = await db.collection("kuchikomi").doc(id); 3 let kuchikomis = []; 4 kuchikomi.get().then((doc) => { 5 if (doc.exists) { 6 kuchikomis.push({ 7 id: doc.id, 8 content: doc.data().content, 9 kind: doc.data().kind, 10 lowTemp: doc.data().lowTemp, 11 Images: doc.data().Images, 12 }); 13 console.log(kuchikomis); //4 14 console.log(kuchikomis[0]); //5 15 } else { 16 } 17 }).catch((error) => { 18 }); 19 return kuchikomis; 20};

結果
ブラウザの表示は、以下の2行のみ表示され、DetailDashboardList.jsの省略の部分は表示されません。

 詳細ページ
最近の投稿

しかし、サーバーを起動させた状態でDetailDashboardList.jsの一部(例えば<h1>タグ内の文言)を編集して保存をかけると省略の部分も表示されるのです!
もちろん本来は、省略の部分も初めから表示させたいです。

コンソールは、以下の順序で呼ばれ、//1と//2はundefinedで、//3は空の配列です。
DetaiDashboard3.js内で示した//1
DetaiDashboard3.js内で示した//2
DetaiDashboard3.js内で示した//3
api.js内で示した//4
api.js内で示した//5

このようなことが起こる原因は、思うように非同期処理が機能していないことが原因と考えたのですが解決策を知りたいです。
自分としては調べ尽くしたのですが分かりませんでした。
初歩的な質問で申し訳ありませんがよろしくお願いします。

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

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

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

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

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

m.ts10806

2022/01/28 03:59

タイトルが気になりました。 非同期処理だからそもそも待ちませんよ。
teradas

2022/01/29 07:39

確かにそうですね。 ご指摘ありがとうございます。
guest

回答1

0

ベストアンサー

思うように非同期処理が機能していないことが原因と考えた

Promiseやasync/awaitの使い方に不備があります。
この辺込み入って学習は大変だし思うように進まないところがありますので、
腰を据えてちょっとずつ理解していきましょう。

js

1// api.js 2export const openDetailDashboard = async id => { 3 // async関数内ではPromiseの処理に失敗したときの挙動であるcatchメソッドを 4 // 普通のtry-catch構文で確保することが可能 5 try { 6 const kuchikomi = await db.collection("kuchikomi").doc(id); 7 8 // await構文はPromiseインスタンスのthenメソッドを叩いて 9 // コールバック関数の第一引数を引っ張り出す効果がある。 10 // つまりこう書き変えることが可能。 11 const doc = await kuchikomi.get(); 12 13 let kuchikomis = []; 14 // これだと要素数1個の配列にしかならんけど大丈夫?どっか勘違いしてるんじゃね? 15 // 多分for...of文でループした方が良いけど、データ構造わからんから放置 16 if (doc.exists) { 17 kuchikomis.push({ 18 id: doc.id, 19 content: doc.data().content, 20 kind: doc.data().kind, 21 lowTemp: doc.data().lowTemp, 22 Images: doc.data().Images, 23 }); 24 } 25 return kuchikomis; 26 } catch (e) { 27 // 失敗時のエラーはデバッグができないので絶対に握りつぶさないこと、 28 // 最低限このようにエラーメッセージを出力するようにする。 29 console.error(e); 30 return []; // この行なしでundefined返すのも正常な気がしないでもない 31 } 32}

そもそも省略が多すぎでpropsで渡したfetch使ってないやんとかツッコミどころはありますが、
openDetailDashboardがまともな値を返してくれないという一点に関しては
これで先に進めるようになるでしょう。


以下解説。

JavaScriptには待つという処理が存在しません。
それを実現する為の手法がイベントです。

JavaScriptに於ける非同期処理は、
「完了条件と実行して欲しい関数」をセットにイベント登録を行い、
処理を全て終了させた後にイベントループ(完了条件を満たしているか巡回する仕組み)で検知してもらって
ぶら下がっている関数を実行してもらうまで待つ必要があります。

よく使われる例としてはこんな感じ

js

1console.log(1); 2setTimeout(() => console.log(2), 0); 3console.log(3); 4// 1 -> 3 -> 2の順番で表示される

「イベント登録します、0ms経過している事を検知したら() => console.log(2)を実行してね」というお願いなので、
console.log(3)までの処理の実行を完了させたNode.jsさん
次にイベントループ巡回を行い、0ms経過というイベント達成条件を精査します。
条件達成しているから() => console.log(2)を実行する。

こういう流れなので絶対に1 -> 3 -> 2の順序での実行となります。
質問文のopenDetailDashboardkuchikomi.get().then(fn)はまさにこれ。
「条件達成したら後でやっておいてね」というお願いをしているわけですが、
returnで値を返す処理の方が先に走ります。
つまり[]の空配列を返す関数になっています。

※new promiseで定義した中身そのものの動作は同期処理で行われるが、
dbアクセスとか挟んでるようなので、イベント登録の向こう側に追いやられて実行が間に合ってなさそう。

回答のコードではthenを叩いている箇所をPromiseのインスタンスと決め打ちし、
一度動作を停止してPromiseの状態が完了になるまで待つawait構文を使って書き直しました。
これにより待つ挙動を実現できます。

投稿2022/01/28 02:27

編集2022/01/28 05:38
miyabi-sun

総合スコア21158

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

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

teradas

2022/01/29 07:37

ありがとうございます! 思うような挙動となりました。 まだまだ初心者ですが教えていただいたことをしっかり学んでいきたいと思います。 早速の回答助かりました。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問