Alex Angas
Alex Angas

Reputation: 60027

How to insert promises during chain execution using node.js Q?

I have a promise chain that requests an RSS URL, parses it for links, then needs to request each link. The first part works great. However I'm having trouble working out how to "insert the promises" that request each link that has been parsed.

I started by generating a simple array of link URLs (preferred method) but couldn't make that work. The code now generates an array of promises to request each URL but I don't know how to make that work either. Perhaps I need to use Q.all() but that seems to be for predetermined functions?

requestRss(rssSourceUrl)
.then(function(links) { 
    // ???
})
.catch(function(error) {
    console.log(error);
})
.done();

function requestRss(url) {
    var deferred = q.defer();
    request(url, function(err, resp, body) {
            if (err || resp.statusCode !== 200) {
                deferred.reject(new Error(resp.statusCode + ' ' + err + ' ' + body));
            } else {
                $ = cheerio.load(body);
                var linkRegex = /<link>([^<$]+)/gim;
                var someLinks = new Array();
                $('item').each(function() {
                    var match = linkRegex.exec($(this).html());
                    if (match) {
                        var link = match[1];
                        someLinks.push(
                            function() { requestSomeLink(link); }
                        );
                    }
                });
                deferred.resolve(someLinks);
            }
        });
    return deferred.promise;
}

function requestSomeLink(url) {
    var deferred = q.defer();
    request(url, function(err, resp, body) {
            if (err || resp.statusCode !== 200) {
                deferred.reject(new Error(resp.statusCode + ' ' + err + ' ' + body));
            } else {
                $ = cheerio.load(body);
                deferred.resolve(body);
            }
        });
    return deferred.promise;
}

Upvotes: 1

Views: 1551

Answers (2)

Bergi
Bergi

Reputation: 664528

The code now generates an array of promises to request each URL

Actually it's an array of function which would each yield a promise for an url request when called. I think you should simply make it an array of links (strings), nothing more - what happens with them is to be determined in another function. So

function requestLinksFromRss(url) {
    …
                    if (match)
                        someLinks.push(match[1]);
    …
    return deferred.promise;
}

Perhaps I need to use Q.all() but that seems to be for predetermined functions?

I don't see what you mean by "predetermined functions". Q.all() just takes an array of promises as its argument. That's what we have here.

requestLinksFromRss(rssSourceUrl).then(function(links) { 
    var promiseArr = links.map(requestSomeLink); // or a loop if you want
    return Q.all(promiseArr);
}).then(function(ressources) {
    // now you have an array of request bodies.
    // Do something with them.
}).catch(console.log.bind(console)).done();

Upvotes: 2

aet
aet

Reputation: 7292

You are not generating an "array of promises", but an array of functions that will ultimately return a promise. Where do you call those functions?

Let's say you go back to returning an array of links, and still have your requestSomeLink(url) function.

requestRss(rssSourceUrl)
.then(function(links) { 
    var index;
    for (index = 0; index < links.length; index++) {
        requestSomeLink(links[index]).then(function(data) {
            // do something with data
        }
    }
})

Upvotes: 1

Related Questions