2014-09-03 103 views
0

我是新的Node.js和承诺(在这里,我使用Q.js)。 我试图使刮板出其具有如下结构的网站:JQuery与嵌套循环的异步承诺

  • main_page:已分类的列表,每个类别都有一个指向存储页面的列表的链接。
  • 商店列表页面:有一个商店列表,每个商店都有一个指向商店详细信息页面的链接。
  • 商店详细信息页面:有我正在寻找的数据。

我做了第一个没有承诺的工作方法,但结果代码非常难看。所以我认为这是使用承诺的好例子。

我不能得到这种方法的工作。当第二个循环完成时,应用程序不会继续(它永远不会执行end()方法)。另外,我不知道如何附加第三个循环。

我该怎么办?

function get(url) { 
    var deferred = Q.defer(); 
    requestify.get(url).then(function(response) { 
     deferred.resolve(cheerio.load(response.getBody())); 
    }); 
    return deferred.promise; 
} 

function process_main_page($) { 
    var promises = []; 
    $('.categories a').each(function(i) { 
     var deferred = Q.defer(); 
     var storesList = $('.store'); 
     get($(this).attr('href')).then(function($) { 
      deferred.resolve(process_stores_list(storesList)); 
     }); 
     promises.push(deferred); 
    }); 
    return Q.all(promises); 
} 

function process_stores_list(storesList) { 
    var promises = []; 
    storesList.each(function() { 

     // Here I need to make another ajax call for each store detail page, which has the data that I need. 

     promises.push(deferred); 
    }); 
    return Q.all(promises); 
} 

function end(res) { 
    var deferred = Q.defer(); 
    fs.writeFile('output.json', JSON.stringify(myGatheredData, null, 4), function(err) { 
     deferred.resolve(function() { 
      res.send('File successfully written! - Check your project directory for the output.json file'); 
     }); 
    }); 
    return deferred.promise; 
} 

app.get('/', function(req, res) { 
    get(url).then(process_main_page).then(end); 
}); 
+1

http:// jsfiddle。net/arunpjohny/v917j5ec/5/ – 2014-09-03 04:15:15

+2

你的代码充满了延期反模式:(考虑阅读并修复它。 – 2014-09-03 06:00:47

回答

2

由于@BenjaminGruenbaum已经评论,你的代码是散落着的deferred antipatternQ.defer()唯一(或多或少)合法使用的是fs.writeFile,但您忘记了在那里处理错误。这只是简单的promisify that API

我无法得到这种方法的工作。

整体结构似乎很好。然而,一些要点:

  • 你似乎从没有从商店页面获取stores_list。您可以获取该页面,但通过类别页面中的var storesList = $('.store');来解决承诺?
  • 您的end方法确实获得了myGatheredData - 结果数组加入了Q.all - 作为其参数传递。它没有任何访问ponse对象的权限。

当第二个循环完成时,应用程序不会继续(它永远不会执行end()方法)。另外,我不知道如何附加第三个循环。

我认为这是原因 - 你可能已经在构建Q.all()数组的延期,但从未解决它们。这使得返回的承诺“挂起”(保持待定),并且从未调用过回调函数。

var write = Q.nbind(fs.writeFile, fs); 
function get(url) { 
    return requestify.get(url).then(function(response) { 
     return cheerio.load(response.getBody())); 
    }); 
} 

function process_main_page($_main) { 
    var promises = $_main('.categories a').map(function(i) { 
     // var storesList = $_main('.store'); // not sure what this did 
     return get($_main(this).attr('href')).then(process_storelist_page); 
    }).toArray(); 
    return Q.all(promises); 
} 
function process_storelist_page($_stores) { 
    return process_stores_list($_stores('a.store').map(function() { 
     return $_stores(this).attr('href'); // whatever? 
    }).toArray()); 
} 

function process_stores_list(storesList) { 
    var promises = $.map(storesList, function(store_url) { 
     // Here make another ajax call for each store detail page 
     return get(store_url).then(process_store_page);); 
    }); 
    return Q.all(promises); 
} 
function process_store_page($_store) { // which has the data that I need. 
    return /* select some data from the page */; 
} 
function save_data(myGatheredData) { 
    return write('output.json', JSON.stringify(myGatheredData, null, 4)).then(function() { 
     return 'File successfully written! - Check your project directory for the output.json file'; 
     }); 
    }); 
} 

app.get('/', function(req, res) { 
    get(url).then(process_main_page).then(save_data).then(function end(result) { 
     res.send(result); 
    }); 
}); 

当然,你也可以用函数表达式而不是我已经使用的函数声明来嵌套所有东西。