如何使用promises返回数组的最终结果?

时间:2014-05-09 19:18:52

标签: javascript node.js request q cheerio

我目前正在尝试在特定网站上返回所有文件名(在每个现有文件夹中)的请求。我的Web应用程序使用NodeJS,Express,Cheerio和Web to scrarape。我的代码首先获取所有文件夹名称的列表。检索文件夹名称列表后,它会进入每个文件夹名称以获取文件名列表并将其存储在“文件”中。阵列。最后,'文件'数组将被发送到客户端。

现在我遇到异步问题,因为我的请求总是会返回一个空文件列表'。我安装了Q节点模块并尝试过使用promises,但是没有运气得到我想要的结果。我仍然是nodeJS的新手,如果有人可以帮助我,我会很喜欢.. :)

exports.getAllImages = function(req, res) {
    var folders = [];
    var files = [];

    //Step 1: Get folder names and store all of them in the 'folders' array
    var foldersUrl = 'http://students.washington.edu/jmzhwng/Images/';
    request(foldersUrl, function(error, response, html){
        if(!error){
            var $ = cheerio.load(html);
        $("a:contains('-')").filter(function(){
            var data = $(this)[0].attribs.href;
            folders.push(data); 
        })

        //Step 2: Using the 'folders' array, get file names in each folder and store all of them in the 'files' array
        for (var i=0; i < folders.length; i++) {
            var imagesUrl = 'http://students.washington.edu/jmzhwng/Images/' + folders[i];
            request(imagesUrl, function(error, response, html){
                if(!error){
                    var $ = cheerio.load(html);
                    $("a:contains('.')").filter(function(){
                        var data = $(this)[0].attribs.href;
                        files.push(data);
                    })
                }
            })
        }

        //Step 3: Return all file names to client-side
        res.json({
            images: files
        }, 200);
        console.log('GET ALL IMAGES - ' + JSON.stringify(files));
    }
})

为了更好的可读性或支持,您可以查看我在此处创建的JSFiddle:http://jsfiddle.net/fKGrm/

1 个答案:

答案 0 :(得分:2)

你不一定需要承诺 - 你已经没有它们的95%了。我认为你知道的主要问题是你的回复是在图片请求回来之前发送的。在发送回复之前,您只需要等待那些完成。

最基本的方法是计算第2步中收到的回调数。当它等于folders.length时,请发送您的回复。

以下是该版本的简化版本:

var request = require('request'),
    cheerio = require('cheerio');

var baseUrl = 'http://students.washington.edu/jmzhwng/Images/';

var files = [];

request(baseUrl, function (error, res, body) {
  var folders = folderLinks(cheerio.load(body));
      count = 0;

  folders.forEach(function (folder) {
    request(baseUrl + folder, function (error, res, body) {
      files.push.apply(files, fileLinks(cheerio.load(body)));

      if (++count == folders.length) {
        console.log(files);
      }
    });
  });
});

function folderLinks ($) {
  return $('a:contains(-)').get().map(function (a) {
    return a.attribs.href;
  });
}

function fileLinks ($) {
  return $('a:contains(.)').get().map(function (a) {
    return a.attribs.href;
  });
}