在for循环中由异步请求填充后无法返回数组

时间:2017-01-23 06:57:27

标签: javascript arrays node.js asynchronous

我试图在每个foreach循环后返回正在填充异步的数组。但是当我回来时,我只得到undefined

以下是代码块:

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();
    }
};

2 个答案:

答案 0 :(得分:1)

首先,请正确缩进您的代码 - 这样更容易理解!

其次,您需要接受代码的异步性。据推测,Rq是一个异步函数:它使整个操作异步。这意味着navigateAndFetchPages需要返回promises,而不是尝试返回数据。

执行此操作的简单方法是使用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();
    }
};

可以Promise.all放在navigateAndFetchPages函数中,但我不会,以防您将来需要访问各个页面的数据。不过,这是你的API,所以这取决于你。

答案 1 :(得分:-1)

您可以将.map()Promise.all()替换为来自.forEach()的{​​{1}},return对象,该对象将包含在.then()链接的结果数组中到.then()

Promise.all()