Bluebird承诺和async.forEach迭代

时间:2016-11-23 23:19:45

标签: javascript node.js bluebird async.js

这是我第一次提问,所以请耐心等待。我试图在node.js中编写内容剪贴簿。我的程序将转到该站点的登录页面,获取下一页的链接并获取下一批页面的链接。我的问题是当我必须遍历一系列链接,转到那个页面,并在那里获取废品信息。我正在尝试async.forEach迭代,但它在我的链式承诺中的最后一个then()之后完成。这里的许多概念对我来说都是新的,所以我确信这段代码很棘手。任何帮助将不胜感激。



var sX = require('scrapper-x');
var request = require('request');
var async = require('async');
var Promise = require('bluebird');
var request = (require('request'));
var colors = require('colors');

var baseURL = 'http://shirts4mike.com';
var arrShirts = [
    {
        link: 'shirt.php?id=101',
        img: 'some img'
    },
    {
        link: 'shirt.php?id=102',
        img: 'some img'
    },
    {
        link: 'shirt.php?id=103',
        img: 'some img'
    }
];

var page = '';

var configMain = {
    repeatItemGroup: '.nav > li',
    dataFormat: {
        link: {
            selector: 'li > a',
            type: 'attr:href'
        }
    }
};

var configShirts = {
    repeatItemGroup: '.products > li',
    dataFormat: {
        link: {
            selector: 'li > a',
            type: 'attr:href'
        },
        img: {
            selector: 'li > a > img',
            type: 'attr:src'
        }
    }
};

var configDetails = {
    repeatItemGroup: '.shirt-details',
    dataFormat: {
        price: {
            selector: '.price',
            type: 'text'
        },
        title: {
            selector: '.shirt-details > h1',
            type: 'text'
        }
    }
};


function getPage(url, config) {
    return new Promise(function(resolve, reject) {
        request(url, function(error, response, body, shirt) {
                if (error) {
                    console.log('error');
                    reject();
                }
                if (!error && response.statusCode == 200) {
                    detail = sX.scrape(body, config);
                    resolve(detail);
                }
            }); 

    });
}

function getDetailPage(arr, config) {
    return new Promise(function(resolve, reject) {
        async.forEach( arr, function( item, callback) {
            request('http://www.shirts4mike.com' + '/' + item.link, function(error, response, body, item) {
                if (!error && response.statusCode == 200) {
                    detail = sX.scrape(body, configDetails);
                    console.log('Item: ', detail);
                }
            }); 
           callback();
        });
        resolve(detail);
    });
}

    getPage(baseURL, configMain).then( function(data) {
        for (var i = 0; i < data.length; i++) {
            //console.log('getMainPage: ', scrappedResult[i].link);
            if (data[i].link.search('shirt') !== -1) {
                page = '/' + data[i].link;
                console.log(page.yellow);
                baseURL += page;
                return baseURL;
            }
        }
    }).then( function(baseURL) {
        return getPage(baseURL, configShirts);
    }).then( function(data) {
        for (var i = 0; i < data.length; i++) {
            //console.log(data[i].link);
            if (data[i].link.search('shirt') !== -1) {
                arrShirts.push(data[i]);
                console.log("arrShirts[" + i + "]: " + arrShirts[i].link);
            }
        }
        return arrShirts;
    }).then( function(arr) {
        return getDetailPage(arrShirts, configDetails);
    }).then(function (data) {
        console.log("end: ", data);
    }).catch( function(err) {
        console.log(err);
    });
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:1)

我建议做一些改变。

  1. 停止使用全局变量或更高范围的变量或未声明的变量。声明使用/需要它们的局部变量,不要与其他函数共享变量。

  2. 不要将异步库与promises混合使用。由于您已经在宣传异步函数,因此使用promise函数来管理多个异步操作。您可以完全从该项目中删除异步库。

  3. 在最低级别实现Promisify,因此所有更高级别的用户都可以直接使用promises。因此,您应该宣传getPage(),然后在request()中使用它,而不是宣传getPage()

  4. 由于您拥有Bluebird promise库,您可以使用它的更高级迭代函数(例如Promise.map())来迭代您的集合,收集所有结果并返回单个承诺,告诉您何时完成所有操作

  5. 使用这些概念,您可以使用以下代码:

    // promisified request()
    function getRequest(url) {
        return new Promise(function(resolve, reject) {
            request(url, function(err, response, body) {
                if (err) {
                    reject(err);
                } else {
                    resolve(body);
                }
            });
    
        });
    }
    
    // resolves to scraped contents for one page
    function getPage(url, config) {
        return getRequest(url).then(function(body) {
            return sX.scrape(body, config);
        });
    }
    
    // resolves to an array of scraped contents for an array of objects 
    // that each have a link in them
    function getDetailPage(arr, config) {
        return Promise.map(arr, function(item) {
            return getPage('http://www.shirts4mike.com' + '/' + item.link);
        });
    }