将异步工作流程更改为Promise(Bluebird)

时间:2015-03-17 02:57:13

标签: javascript node.js asynchronous promise bluebird

我一直试图绕着Promises。对于我理解的基本概念,但一旦嵌套,我有点困惑。任何反馈都表示赞赏

这是我试图重构为Promises(bluebird)的代码

var getIndividualData = function(url, doneGetIndividualData) {
    var $, data;

    request(url, function(err, res, body) {
        if (!err && res.statusCode === 200) {
            $ = cheerio.load(body);

            data = {
                title: $("#itemTitle").children()["0"].next.data,
                condition: $("#vi-itm-cond").text(),
                price: $("#prcIsum_bidPrice").text(),
                imgUrl: $("#icImg")[0].attribs.src,
                createdAt: chance.date(),
                likes: chance.integer({min: 0, max: 1000})
            };

            doneGetIndividualData(null, data);
        } else {
            doneGetIndividualData(err);
        }
    });
};

var getListing = function(url, doneGetListing) {
    var $;
    var links = [];

    request(url, function(err, res, body) {
        if (!err && res.statusCode === 200) {
            $ = cheerio.load(body);

            $('.vip').each(function(i, el) {
                if (i < 15) {
                    links.push(el.attribs.href);
                }
            });

            async
                .concat(links, getIndividualData, function(err, result) {
                    return doneGetListing(null, result);
                });
        } else {
            doneGetListing(err);
        }
    });
};

var putToMongo = function(err, result) {
    if (devConfig.seedDB) {
        mongoose.connect(devConfig.mongo.uri);

        Item.find({}).remove(function(err, items) {
            Item.create(result, function(err, items) {
                console.log('done');
                process.kill();
            });
        });
    }
};

async
    .concat(urls, getListing, putToMongo);

1 个答案:

答案 0 :(得分:2)

首先要做的是将request包装在返回promise的内容中。许多承诺图书馆都有实用工具,用于宣传&#34;异步函数,但我不认为它会在这里工作,因为request将两个成功值传递给它的回调:

var requestAsync = function(url) {
    return new Promise(function (resolve, reject) {
        request(function (err, res, body) {
            if (err) {
                reject(err);
            }
            resolve({ res: res, body: body});
        });
   });
};

一旦完成,就会变得容易多了:

var getIndividualData = function(url) {
    return requestAsync(url).then(function (result) {
        if (result.res.statusCode === 200) {
            var $ = cheerio.load(result.body);

            return {
                title: $("#itemTitle").children()["0"].next.data,
                condition: $("#vi-itm-cond").text(),
                price: $("#prcIsum_bidPrice").text(),
                imgUrl: $("#icImg")[0].attribs.src,
                createdAt: chance.date(),
                likes: chance.integer({min: 0, max: 1000})
            };
        }

        throw new Error("Individual data status code: " + result.res.statusCode);
    });
};

var getListing = function(url, doneGetListing) {
    return requestAsync(url).then(function (result) {
        if (result.res.statusCode === 200) {
            var $ = cheerio.load(result.body),
                promises = $('.vip').filter(function (i) { 
                    return i < 15;
                }).map(function (i, el) {
                    return getIndividualData(el.attribs.href);
                });

            return Promise.all(promises);
        }

        throw new Error("Listing status code: " + result.res.statusCode);
    });
};

var putToMongo = function(result) {
    if (devConfig.seedDB) {
        mongoose.connect(devConfig.mongo.uri);

        Item.find({}).remove(function(err, items) {
            Item.create(result, function(err, items) {
                console.log('done');
                process.kill();
            });
        });
    }
};

Promise.all(urls.map(getListing))
.then(putToMongo)
.catch(function (err) {
    // handle error
});