2017-01-23 8 views
0

ループがforeachのループごとに非同期に配置されている配列を返そうとしています。しかし、私が帰ってくると、私はundefinedしか得られません。forループ内で非同期要求によってデータが取り込まれた後に配列を返すことができません

var navigateAndFetchPages = function (data) { 
    var countryPages = []; 
    data.forEach(function (val) { 
    Rq(val.esomar_url) 
     .then(function (data) { 
      var $ = cheerio.load(data), 
       pages_elem = $('.mt0.mb0-5.pt0').find('a').not('.active'); 
      countryPages.push({country_name: val.country_name, links: pages_elem}); 
    }) 
    }); 
    return countryPages; 
}; 


var scraper = { 
    extract: function (dir) { 
     return landingPage(dir) 
      .then(function (countries) { 
       return navigateAndFetchPages(countries) 
      }) 
      .then(function (p) { 
       p() 
      }) 
      .catch(); 
    } 
}; 
+0

_ "私が戻ったとき、私は' undefined'しか得られません "_値はどこで' navigateAndFetchPages'から返されましたか? – guest271314

+0

申し訳ありませんが、戻り値を追加しました。そして、非同期procが完了する前に値が返されていることがわかります。しかし、私はforeachブロック内に戻ることもできません..今私は何をするつもりです... – ChanX

+0

Doそのような配列を直接返す必要があるか、または約束やコールバック関数を使用するようにコードを構造化できますか? (「通常の非同期処理として」 – nnnnnn

答えて

-1

あなたは置き換えることができ.map().forEach()ためPromise.all()Promise.all()

var navigateAndFetchPages = function(data) { 

    return Promise.all(data.map(function(val) { 
    return Rq(val.esomar_url) 
     .then(function(data) { 
     var $ = cheerio.load(data), 
      pages_elem = $('.mt0.mb0-5.pt0').find('a').not('.active'); 
      return { 
      country_name: val.country_name, 
      links: pages_elem 
      }; 
     }); 
    })); 

}; 

navigateAndFetchPages 
.then(function(countryPages) { 
    // do stuff with `countryPages` 
}) 
.catch(function(err) { 
    console.log(err); 
}); 
1

最初にチェーン.then()で得られた配列内に含まれる.then()からreturnオブジェクト:以下

は、コードブロックでありますまず、コードを適切にインデントしてください - それははるかに簡単です!

第2に、コードの非同期性を取り入れる必要があります。 Rqは、おそらく、非同期関数です。これは、操作全体を非同期にします。つまり、navigateAndFetchPagesは、データを返そうとするのではなく、約束を返す必要があります。

これを行う簡単な方法はArray#mapです。

var navigateAndFetchPages = function(data) { 
    return data.map(function(val) { 
    return Rq(val.esomar_url).then(function(data) { 
     var $ = cheerio.load(data), 
      pages_elem = $('.mt0.mb0-5.pt0').find('a').not('.active'); 
     return { 
      country_name: val.country_name, 
      links: pages_elem 
     }; 
     }) 
    }); 
}; 

navigateAndFetchPagesへの呼び出しの結果は、約束の配列になります。

あなたはPromise.allを完了するために、それらすべてを待つことができます。

Promise.all(navigateAndFetchPages(data)).then(function(result) { 
    // result is an array of objects containing your data 
}); 

更新された質問は、これは約束のチェーンで呼び出さそのものであることを示しています。これに対処するのは簡単です:

var scraper = { 
    extract: function (dir) { 
     return landingPage(dir) 
      .then(function (countries) { 
       return Promise.all(navigateAndFetchPages(countries)); 
      }) 
      .then(function (p) { 
       p() 
      }) 
      .catch(); 
    } 
}; 

あなたnavigateAndFetchPages関数内Promise.allを置くこともできますが、私ではない、場合にあなたは将来的には個々のページのデータにアクセスする必要があります。あなたのAPIですが、それはあなた次第です。

+0

私は急いで答えを得ることができました.. 'Rq'は' request-promise'のインスタンスです – ChanX

+1

@ guest271314良いスポット:固定。 – lonesomeday

+0

@ guest271314はい...もう一度、ありがとうございます。 – lonesomeday

関連する問題