防止使用迭代的JavaScript中的嵌套回调

时间:2014-11-25 14:45:49

标签: javascript jquery node.js promise cheerio

目前我使用promises试图阻止我的代码中嵌套回调的需要,但我遇到了挫折。在这种情况下,我使用node的request-promise和cheerio来模拟服务器上的jQuery。但是,在某些时候我需要调用jQuery.each()来为每个<a>元素创建一个请求。有什么方法可以使用promises来阻止这种嵌套回调吗?

request("http://url.com").then(function (html) { 
    var $ = cheerio.load(html);
    var rows = $("tr.class a");
    rows.each(function (index, el) {

        //Iterate over all <a> elements, and send a request for each one.
        //Can this code be modified to return a promise?
        //Is there another way to prevent this from being nested?

        request($(el).attr("href")).then(function (html) {
            var $ = cheerio.load(html);
            var url = $("td>img").attr("src");
            return request(url);
        })
        .then(function (img) {
            //Save the image to the database
        });
    });
});

2 个答案:

答案 0 :(得分:1)

假设Bluebird承诺(其他库中的代码类似):

Promise.resolve(request("http://url.com").then(function (html) { 
    var $ = cheerio.load(html)("tr.class a");
})).map(function(el){ // map is `then` over an array
    return el.href;
}).map(request).map(function(html){
    return cheerio.load(html)("td>img").src;
}).map(request).map(function(img){
    // save to database.
});

或者,您可以为单个链接定义操作,然后处理这些操作。它看起来很相似。

答案 1 :(得分:0)

这是我最终得到的最佳解决方案。我做的一些偶然更改包括使用url.resolve来允许相对URL工作。

var $ = require('cheerio');
var request = require('request-promise');
var url = require('url');

var baseURL = "http://url.com";

request(baseURL).then(function (html) {
    $("tr.class a", html).toArray(); 
}).map(function (el) {
    return request(url.resolve(baseURL, jq.attr("href")));
}).map(function (html) {
    var src = $("td>img", html).attr("src");
    return request(url.resolve(baseURL, src));
}).map(function (img) {
    //Save the image to the database
});

感谢Benjamin Gruenbaum将我改为bluebird中的.map()方法。