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

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

ただいまの
回答率

90.51%

  • JavaScript

    20383questions

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

  • Node.js

    2358questions

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

JavascriptのPromiseについて

解決済

回答 3

投稿

  • 評価
  • クリップ 1
  • VIEW 598

kazzzstudio

score 86

Javascript(Nodejs)とcheerio-httpcliを使ってスクレイピングの処理を書いているのですが、実行順序がコントロールできずに途中でプログラムが終わってしまいます。

var loopProcess = function(callback) {
    return new Promise(function(resolve, reject) {
        for (i = 0; i < _keyword_array.length; i++) {
        console.log("Inside Loop")
        // 指定された検索エンジンによって処理を分ける
            if (_search_engine == "google") {
                goGoogle(_keyword_array[i], _user_agent, _check_keyword)
            }
            else {
                goYahoo(_keyword_array[i], _user_agent, _check_keyword)
            }
        }
    })
}

// 結果を出力する
var finishProcess = function() {
    return new Promise(function(resolve, reject) {
        _result_html += "</table>"
        _result_area.innerHTML += _result_html
        console.log("finish end process")
    })
}

loopProcess().then(finishProcess())

_keyword_arrayには3件のテストデータが入っており、for文は3回回らなければなりません。
しかし、
Inside Loopのログが1回だけ出て、その後は、finish end processと出て終わってしまいます。
何か書き方が悪いことはわかるのですが、どこをどう直せばいいのかがわかりません。

よろしくお願いします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

+5

何か書き方が悪いことはわかるのですが、どこをどう直せばいいのかがわかりません。

コードを見る限りPromiseについて分かっていないで書いているようなので、
まずはPromiseについてまずは学ぶと良いのではないでしょうか。
そして、その後、必要であれば質問を再度されていはいかがですか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/03/27 14:22

    まさにおっしゃる通りであることはわかっていたのですが、納期が迫っていたため止むを得ずお聞きしたという次第です。なんとか動くコードが作れたのでよかったです。これから勉強します。

    キャンセル

checkベストアンサー

+2

各変数の中身が分からないので、
回答者が最後まで面倒みるのは不可能です。

Promiseの書き方は試行錯誤の後が見れますが、sousukeさんの仰るように
何か簡単なresolveやrejectを発火するコードを書いて動作を確かめてみてください。

さて、それ以外のどう見ても駄目そうな箇所を幾つか突っ込みます。

  • var loopProcess = function(callback)このコールバック関数は何?
  • goGoogleとgoYahooって非同期な処理じゃないの?
  • .then(finishProcess())何も待たずに発火して評価開始してる件

var loopProcess = function(callback)このコールバック関数は何?

試行錯誤の後でしょうね。
これは普通の非同期処理を書く時のやり方で、
新しいPromiseを使った非同期処理の時は不要です。

コードを見せる時に削っておきます。

goGoogleとgoYahooって非同期な処理じゃないの?

質問文に「Inside Loopのログが1回だけ出て」という記載があるのでほぼ確定でしょう。
goGoogleがコールバック関数を要求するのか、はたまたPromiseを返すのかでまた分岐しますが、
全て実行完了するのを待ってからresolve(value)にするべきでしょう。

もっと言うなら、お外のスコープで宣言した_result_htmlを書き換える設計は死ぬほどダサいです。
resolve(value)の中身を_result_htmlとして実行するべきでしょう。

更に一手進めてasync / awaitを使ってリファクタリングすればこんな感じになると想定されます。

// loopProcess :: Object -> Promise
const loopProcess = async options => {
  const {search, keywords, user_agent, check_keyword} = options
  const results = []
  for (const keyword of keywords) {
    console.log("Inside Loop")
    // なんでキーワード全て同じ検索エンジンになるの?外からもってきなさい
    // searchはPromiseを返す関数と決め打ちしてawaitで待つ
    const result = await search(keyword, user_agent, check_keyword)
    results.push(result)
  }
  return results
}

// 恐らくgoGoogleとgoYahooもリファクタリングの必要あり
const search = _search_engine == "google" ? goGoogle : goYahoo
const options = {
  search,
  keywords: _keyword_array,
  user_agent: _user_agent,
  check_keyword: _check_keyword
}
loopProcess(options)

.then(finishProcess())何も待たずに発火して評価開始してる件

発火させてはいけません。
前のPromiseのresolve(value)の第一引数(value)がthenの第一引数に格納されて発火される作りになっているからです。

このように記述してください。

// Promiseである必要はないので普通の関数にした
finishProcess = (html, area, results) => {
  // TODO: resultsを加工する
  const result_html = toResultHTML(results)
  area.innerHTML += html + result_html + "</table>"
  console.log("finish end process")
}

// options変数は前章を参考
// _result_htmlと_result_areaはfn.prototype.bindを使って束縛する
loopProcess(options)
  .then(finishProcess.bind(null, _result_html, _result_area))

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/03/27 14:20

    わかりやすいご説明ありがとうございます!

    キャンセル

+2

resolve()とreject()してないですね…。
promiseは簡単にいうと
・resolveしたときにthenコールバックに入る
・rejectしたときにcatchコールバックに入る
というものですよ。

両方とも呼んでないので意味をなさないコードになっています。
使い方を調べた方がよろしいかと。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/03/27 14:21

    勉強が足りませんでした。もっとよく調べます。

    キャンセル

同じタグがついた質問を見る

  • JavaScript

    20383questions

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

  • Node.js

    2358questions

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