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

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

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

for文は、様々なプログラミング言語で使われている制御構造です。for文に定義している条件から外れるまで、for文内の命令文を繰り返し実行します。

JavaScript

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

非同期処理

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

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

解決済

2回答

1667閲覧

配列がfor文で回らない、Promiseが機能しないときがある

cerasusflorere

総合スコア13

for

for文は、様々なプログラミング言語で使われている制御構造です。for文に定義している条件から外れるまで、for文内の命令文を繰り返し実行します。

JavaScript

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

非同期処理

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

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

0クリップ

投稿2021/10/02 03:13

前提・実現したいこと

現在フロント側にjavascriptを用いて、SNSアプリのようなものを作っています。

ユーザーは他のユーザーの投稿をお気に入り登録でき、お気に入り一覧画面で閲覧できるようにしたいと考えています。

DBには投稿情報(写真管理サイトで管理する写真データのURL含む、一覧表示時に写真管理サイトの該当URLを参照しています)がすべて入ったAコレクション、お気に入り登録した作品についてユーザーIDと投稿ID(Aコレクションで付与される)が入ったBコレクションがあります。

お気に入り一覧画面では

  1. function Favorites()
    Bコレクションから投稿IDを取得、favorite_data_id配列に挿入する。
  2. function FavoriteDatas()

Aコレクションから全投稿内容を取得、favorite_data_id配列のいずれかとidが一致した投稿をfavorite_datas配列に挿入する。
3. function addToList(now_datas)
引数now_datas配列でfor文を回し、画面上に表示する。

という順序で最初の画面は表示させたいと考えています。

3.function addToList(now_datas)でfavorite_datas配列をそのまま利用しない理由は、絞り込み検索結果表示の際にもaddToList関数を利用したいためです。

発生している問題

配列がfor文で回らないのとPromiseが機能しないときがあるのは別問題だとは思ったのですが、どのような時にfor文で回らないのか、Promiseが機能しないのか判別できなかったので、一度に質問しています。

  1. 配列がfor文で回らない

必ず起こります。
3.function addToList(now_datas)で引数now_datas配列が回りません。
Promiseが機能しているときにはfor文の直前でnow_datas配列を取得すると、now_datas配列にデータは入っているのですが、インデックス番号を指定してもundefinedになり、for文は回りません。
2. Promiseが機能しない
時々起こります。
今回初めてPromiseを使用しており、まだPromiseが確実に機能する状態のコードを書けたことないのですが、そもそも3.function addToList(now_datas)到達時にfavorite_datas配列が空の状態です。
2.function FavoriteDatas()到達時にfavorite_data_id配列はセットされています。

どちらかだけでも良いので、教えていただけないでしょうか。

該当のソースコード

javascript

1 let favorite_data_id = []; // お気に入り登録してあるworkid 2 let favorite_numbers = 0; // お気に入り登録してある数 3 let favorite_datas = []; // お気に入り登録してある全作品 4 window.onload = allDatas(); // 画面ロード時に実行 5 6 function Favorites() { 7 const url = '/Favorites'; // 通信先 8 const req = new XMLHttpRequest(); // 通信用オブジェクト 9 10 req.onreadystatechange = function() { 11 if(req.readyState == 4 && req.status == 200) { 12 const datas = JSON.parse(req.response); 13 for(let i in datas) { 14 const data = datas[i]; 15 favorite_data_id[favorite_numbers] = data.workid; 16 favorite_numbers++; 17 } 18 } 19 } 20 req.open('GET', url, true); 21 req.send(); 22 } 23 24 // 全データの取得 25 function FavoriteDatas() { 26 console.log(favorite_data_id); 27 const url = '/AllDatas'; // 通信先 28 const req = new XMLHttpRequest(); // 通信用オブジェクト 29 30 req.onreadystatechange = function() { 31 if(req.readyState == 4 && req.status == 200) { 32 const datas = JSON.parse(req.response); 33 all_datas = datas; 34 for(let i in all_datas){ 35 for(let j in favorite_data_id){ 36 if(all_datas[i]._id == favorite_data_id[j]){ 37 favorite_datas[j] = all_datas[i]; 38 } 39 } 40 } 41 } 42 } 43 req.open('GET', url, true); 44 req.send(); 45 } 46 47 // 表示 48 function addToList(now_datas) { 49 for(let i in now_datas){ 50 // 表示 51 } 52 } 53 54 function allDatas(){ 55 new Promise((resolve) => { 56 Favorites(); 57 resolve(); 58 }).then(() => { 59 FavoriteDatas(); 60 }).then(() => { 61 addToList(favorite_datas); 62 }); 63 }

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

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

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

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

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

itagagaki

2021/10/02 03:18

デバッグをしたことはないのですか?
Lhankor_Mhy

2021/10/02 03:42

とりあえず、返り値のない関数が散見されるのですが、その辺は大丈夫なんですか?
cerasusflorere

2021/10/02 03:51

itagagaki様 デバッグというのはconsole.log()で何か書いて、開発ツールで見ることでしょうか? それであればしたことはあります。 Lhankor_Mhy様 setTimeoutで処理を遅らせていた時には表示ができていたのですが(Promiseに変更しようといじった結果表示できなくなりました。別のページでは変わらず返り値を設定しなくともsetTimoutで表示できてはいます)、関数には必ず返り値が必要なのでしょうか?
think49

2021/10/02 04:03 編集

直接的な問題ではありませんが、関数名が名詞なので名前から機能が読み取れないのも気になりました。 関数名は動詞にすると良いです。
Lhankor_Mhy

2021/10/02 04:14

> 関数には必ず返り値が必要なのでしょうか? いえ、返り値を返さないなら undefined が返るだけです。それを想定しているのであれば、問題ないですが、たとえば FavoriteDatas() が undefined を返すのは想定通りなのかな、ということが気になっているという話です。
cerasusflorere

2021/10/02 06:09

think49様 関数名は動詞にするのがマナーとは知りませんでした。教えていただきありがとうございます。
think49

2021/10/02 06:25 編集

@cerasusflorere さん マナーというより「名前と内容が一致していない」という意味です。 「お気に入りのデータ(FavoriteDatas)」という名前の変数があったとして、格納されている内容を console.log(お気に入りのデータ) で確認したところ、データではなく、関数でした。 「お気に入りのデータ」になにがしかの処理をする関数と思われますが、「お気に入りのデータ」の名前から処理内容が読み取れません。 「お気に入りのデータを取ってきてくれ(fetchFavoriteData)」なら名前から処理内容を想像できます。 ("Data" は複数形の為、"s" は不要です)
cerasusflorere

2021/10/08 02:44

think49様 ありがとうございます。今後は動詞で書こうと思います。
guest

回答2

0

ku__ra__geさんのご回答に追加して、thenメソッドのハンドラ関数が値を返していないことを指摘しておきます。

何も返さなかった場合、 then によって返される Promise は undefined の値で解決します。

Promise.prototype.then() - JavaScript | MDN

これはつまり、.then(() => {FavoriteDatas();})は、FavoriteDatasの処理終了を待たずに即座に解決されるということです。

投稿2021/10/02 05:01

編集2021/10/02 05:06
Lhankor_Mhy

総合スコア36117

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

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

cerasusflorere

2021/10/02 06:07

回答してくださいありがとうございます。 FavoriteDatas関数に返り値を設定すれば、処理終了を待ってもらえるのでしょうか? それともなんらかの数値をthenメソッド内でreturnするのでしょうか? 最初のチェーン以降の処理の待ち方は調べたのですが、分からず、特に何もしなくとも大丈夫なものなのかと思っておりました。 教えていただけると幸いです。
Lhankor_Mhy

2021/10/02 06:25 編集

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/then#return_value こちらに書いてあるとおり、pending の Promise を返せば、解決まで待つようになります。 ですので、FavoriteDatas() の処理終了時に解決するような Promise を渡せばいいです。 まずは、Promise を返す XMLHttpRequest() のラッパー的な関数を書いてしまった方が楽なような気がしますね。 「Promise XMLHttpRequest」でググれば、参考になるコードが見つかるのではないかと思います。 --- IE11 に対応してないですが、fetch() は Promise を返すので、このようなコードを書く時にかなり楽ができます。 https://developer.mozilla.org/ja/docs/Web/API/fetch
cerasusflorere

2021/10/08 02:47

ありがとうございます。 しっかり勉強したいと思います。
guest

0

ベストアンサー

Promiseが機能しない
時々起こります。
今回初めてPromiseを使用しており、まだPromiseが確実に機能する状態のコードを書けたことないのですが、
そもそも3.function addToList(now_datas)到達時にfavorite_datas配列が空の状態です。
2.function FavoriteDatas()到達時にfavorite_data_id配列はセットされています。

Promiseの使い方が間違っているからです。
単純化した例を以下に示します。

javascript

1// 質問者さんが書いているコード 2// これを実行すると、<<B>> → <<A>> の順に処理が実行されます。 3// つまりXMLHttpRequestの通信結果を受け取る前に、then(()=>{……の処理が実行されてしまうということです。 4new Promise((resolve) => { 5 6 const req = new XMLHttpRequest(); // 通信用オブジェクト 7 req.onreadystatechange = function() { 8 if(req.readyState == 4 && req.status == 200) { 9 console.log("<<A>>"); 10 } 11 } 12 req.open('GET', url, true); 13 req.send(); 14 15 resolve(); 16 17}).then(()=>{ 18 console.log("<<B>>"); 19}); 20 21// 質問者さんが求めているであろう動作を行うコード 22// これを実行すると、<<A>> → <<B>> の順に処理が実行されます。 23new Promise((resolve) => { 24 25 const req = new XMLHttpRequest(); // 通信用オブジェクト 26 req.onreadystatechange = function() { 27 if(req.readyState == 4 && req.status == 200) { 28 console.log("<<A>>"); 29 resolve(); 30 } 31 } 32 req.open('GET', url, true); 33 req.send(); 34 35}).then(()=>{ 36 console.log("<<B>>"); 37});

Promiseの概念を理解できてないようなので、Promiseを学習してください。
Promise - JavaScript | MDN

あとjavascriptで配列の反復処理はfor~ofを使ってください。
for~inは配列の反復処理を正しく行えるとは限りません。

配列の繰り返しと for...in

注: for...in はインデックスの順序が重要となる 配列 の繰り返しには使うべきではありません。

投稿2021/10/02 04:15

編集2021/10/02 04:20
ku__ra__ge

総合スコア4524

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

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

cerasusflorere

2021/10/02 05:51

回答してくださり、ありがとうございます。 Promiseは機能するようになりました。 関数実行終了まで待ってくれるわけではないのですね。勉強します。 for...ofで実装してみたのですが、valueでないためか、 for(let data of now_datas){ console.log(data); } としてもdataがundefinedになってしまいます。 forEach文にしてもPromiseからの実行では回りません。 質問では書かなかったのですが、投稿にteratailでいうタグのようなものをつけており、タグ検索を行うのですが、この時は回ります。 質問の内容が変わってしまうので、別質問に分けようと思います。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問