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

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

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

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

Q&A

解決済

2回答

6959閲覧

配列をループして非同期でデータを取得し、ループが終わるまで待つ方法

flaumig

総合スコア67

JavaScript

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

0グッド

0クリップ

投稿2018/02/15 11:47

URLが複数含まれる配列をループで回しながら、
URLごとにHTMLを取得し、そのHTMLから取得したデータを1つの配列として返す、という処理を実装したいです。

■呼び出し元

JavaScript

1let titles = getPageTitle(links); 2console.log("titles : " + JSON.stringify(titles));

■データ取得処理

JavaScript

1const getPageTitle = (links: Array) => { 2 console.log("getPageTitle start"); 3 let titles = []; 4 for (let i = 0; i < links.length; i++ ) { 5 const url = links[i]; 6 console.log("url : " + url); 7 const pageContent = fetchHtml(url); 8 if (pageContent != null) { 9 pageContent.then(function(value) { 10 console.log("--------------------------------------------------"); 11 let parser = new DOMParser() 12 let doc = parser.parseFromString(value, 'text/html'); 13 let title = doc.title; 14 console.log("title : " + title); 15 console.log("--------------------------------------------------"); 16 titles.push({title:title}); 17 }); 18 } else { 19 console.log("pageContent is null"); 20 } 21 } 22 console.log("getPageTitle end"); 23 return titles; 24}

ところが、上記のコードを実行すると下記のように、
先に呼び出し元のconsole.logが呼び出されてしまいます。

■現在の挙動

getPageTitle start url : /sample1.html url : /sample2.html getPageTitle end titles : [] -------------------------------------------------- title : サンプルタイトル1 -------------------------------------------------- -------------------------------------------------- title : サンプルタイトル2 --------------------------------------------------

これを下記のような挙動にしたいのですがどうしたら良いでしょうか?
ご存知の方がいらっしゃいましたらどうかアドバイスをお願いいたします。

■期待する挙動

getPageTitle start url : /sample1.html url : /sample2.html -------------------------------------------------- title : サンプルタイトル1 -------------------------------------------------- -------------------------------------------------- title : サンプルタイトル2 -------------------------------------------------- getPageTitle end titles : [{"title":"サンプルタイトル1"}, {"title":"サンプルタイトル2"}]

利用しているライブラリは下記の通りです。

  • Node.js
  • React
  • Redux-Observable
  • Redux
  • RxJS
  • Next.js
  • isomorphic-fetch

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

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

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

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

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

guest

回答2

0

ベストアンサー

Promiseやasync/awaitはコールバック地獄から抜け出る特効薬ではありませんよ。
一度非同期の世界に入ったものは、同期処理の世界に戻す事は出来ませんよ。

コードが無限にネストせずに綺麗に書けるというメリットはありますが、
コールバック関数の中に引きこもらなければならないので、
普通の書き方からは切り離されるという問題は何も解決していません。

で、async/awaitは使えるんですかね?
使える想定で書き直すとこんな感じになります。

JavaScript

1// asyncキーワードを使いpromiseを返す関数として定義しなおします。 2const getPageTitle = async (links: Array) => { 3 console.log("getPageTitle start") 4 let titles = [] 5 6 // 配列を参照する場合はfor...ofの方がカワイイです。 7 for (let url of links) { 8 console.log("url:", url) 9 try { 10 // どうせおまえPromiseだろ?というわけでawaitで受け取ります。駄目なら勝手にcatchに入ります。 11 const value = await fetchHtml(url) 12 console.log("--------------------------------------------------"); 13 const parser = new DOMParser() 14 const doc = parser.parseFromString(value, 'text/html') 15 const title = doc.title 16 console.log("title:", title) 17 console.log("--------------------------------------------------") 18 titles.push({title}) 19 } catch (e) { 20 console.log(e) 21 } 22 } 23 24 console.log("getPageTitle end"); 25 return titles; 26} 27 28// お外でthenを使いつつ確認してください。 29getPageTitle(['http://google.com']) 30 .then(titles => { 31 console.log(titles) 32 })

投稿2018/02/15 12:43

miyabi-sun

総合スコア21158

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

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

flaumig

2018/02/15 14:16

ご回答ありがとうざいます! アドバイスを頂ければと思っておりましたが、 きちんとしたコードを記載いただけて本当に嬉しかったです。 ご指摘通りPromiseやasync/awaitを使うのだろうなとは考えておりましたが、 よく理解していなかったため、トライ&エラーを繰り返しても解決できず途方にくれておりました。 本当に、本当にありがとうございます! 理解しないことには次また同じ問題でつまづくと思いますので、 きちんと自分でも勉強したいと思います。
guest

0

promise.allで非同期処理がすべて終わるのを待ってみては?

投稿2018/02/15 11:59

yambejp

総合スコア114583

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

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

flaumig

2018/02/15 14:15

ご回答ありがとうございます。 Promiseはなんとなく知っていましたが、Promise.allというものもあるのですね。 調べてみます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問