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

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

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

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

Q&A

解決済

2回答

324閲覧

Node.js : Promise の中で配列に対する処理を行ったあとにresolveしたい

dwayne_johnson

総合スコア86

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

0グッド

0クリップ

投稿2018/08/23 03:28

Promiseオブジェクトのなかで配列を返したいのですが、その前に配列に対して処理を行ってから返したいです。

const makeAgenda = (cheerio_object) => { return new Promise((resolve, reject) => { console.log("In makeAgenda"); const $ = cheerio_object; const agenda = []; $('div.article-main section').map((i, node) => { return $(node).find('h2').map((i, h2) => { const array = { "h2": $(h2).text(), "h3": [] } const count = $(node).find('h3'); if (count.length >= 1) { $(node).find('h3').map((i, h3) => { return array.h3.push($(h3).text()); }) } return agenda.push(array); }) }) resolve(agenda); }) }

cheerio_objectというのは、cheerioというライブラリを用いて、Node.js上でhtmlを扱う際に、jQueryのように扱えるようにしたものです。

agendaという配列を定義して、htmlよりh2,h3要素をここに抜き出し、目次の配列をつくり、それを返すといった処理を行いたいと思っています。

現状のコードでは、agendaが未処理のまま返ってしまいます。
Promiseについて絶賛学習中の身なのですが、どうしてもこれを解決することができず困っています。配列、というかmapを行う際は、Promise.allを使った方が良い的な記事も見かけたのですが、いまいち自分のやりたい処理を実現できず。。

ご指南いただきたいです。
よろしくお願いします。

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

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

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

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

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

guest

回答2

0

ベストアンサー

agendaが未処理に関してはどうやって検証しましたか?
ところどころ怪しいコードと感じる箇所はあるものの、動きはしそうですが……
ただまぁ、問題があったとしてももう少しcheerioのメソッドの使い方を勉強すれば普通に解決することだと思います。

そしてcheerioのmapメソッドは同期的な処理なのでPromise不要というかむしろ邪魔です。
原因はこれの外側の使い方にある可能性が高いと思います。


以上を踏まえてmapの解説

mapには地図という意味の他に、
工場で上から雛形を押さえつけて製品を作ってしまうという意味があります。
プログラミングに於けるmapは後者の意味合いであり、配列の各要素全てにA→Bに変換する関数をあてがって、同じ要素数の別配列を作り直すというものを指します。
探せばJavaScript、PHP、Ruby、Python、Haskell、Elixir…etc、と今どきの言語ならば探せば結構見つかります。

この観点で見ていきましょう。
例えば[].push(123)の戻り値は[123]ではなく、新しい配列の要素数である1ですが、mapの動きとしてふさわしいものですか?

もしこの処理を軸に書き直すのであればeachを使いましょう。
こちらは日本語訳すると「各々」を表すもので、戻り値を使わないので捨てるという思想になっています。
下記はeachを軸に書き直したものになります。未検証ですがそこそこいい感じのコードになったんじゃないかと思います。

※Promise?同期的な関数なので即刻削除

JavaScript

1// もし文字列を引数にする関数が作りたかったらstringという名前にするの?違うよね?なら最初から$でおk 2// かっこつけてHaskell風の表記で書いてみる 3// makeAgenda :: CheerioObject -> Object 4const makeAgenda = $ => { 5 // PromiseでなくA to Bの関数になったんだからconsole.logとかいらないよね 6 const agenda = []; 7 // 慣習として使わない引数は`_`で受ける 8 $('div.article-main section').each((_, node) => 9 agenda.push({ 10 'h2': $(node).find('h2').text(), 11 // こことかまさにmapの使い所さんじゃない? 12 'h3': $(node).find('h3').map((_, h3) => $(h3).text()).get() 13 }) 14 ); 15 return agenda; 16}

投稿2018/08/23 04:29

編集2018/08/23 04:37
miyabi-sun

総合スコア21158

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

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

dwayne_johnson

2018/08/24 10:02

すみません、エラーに関しては別の箇所に問題がありました。 お騒がせしました。 同期的、非同期的の区別が甘かったです。 お手直しいただけたことが、大きく勉強になりました。 コード中のコメントも、引数の文字の考え方や慣習など、初歩的な箇所ではありますが至らないところがあったものをご指摘いただけたため、学びになりました。 ありがとうございました。
guest

0

コード上はあっているように見えます。makeAgendaをそのまま試しに実行しましたがちゃんと取れるようです。

const cheerio = require('cheerio') makeAgenda(cheerio.load(` <div class='article-main'> <section> <h2 class="title">Hello world1</h2> <h3 class="title">Hello world2</h3> <h3 class="title">Hello world3</h3> </section> </div> <div class='article-main'> <section> <h2 class="title">Hello world4</h2> <h3 class="title">Hello world5</h3> <h3 class="title">Hello world6</h3> </section> </div> `)).then(r => {console.log(r)})

結果

> [ { h2: 'Hello world1', h3: [ 'Hello world2', 'Hello world3' ] }, { h2: 'Hello world4', h3: [ 'Hello world5', 'Hello world6' ] } ]

おそらく処理対象のHTMLに期待する要素がないのではないでしょうか?(class='article-main'など)

投稿2018/08/23 03:53

denzow

総合スコア640

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

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

dwayne_johnson

2018/08/24 09:57

すみません、別の箇所に問題がありました。。。 わざわざ試していただき、ありがとうございました。 お蔭様で、別の箇所のエラーを疑うことができ、無事解決しました。 おさわがせしました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問