NodeJs异步瀑布(回调方法不是函数)

时间:2017-03-13 11:54:17

标签: node.js async.js waterfall

我在使用异步瀑布时遇到问题,我发现在调用第二个回调(cbNumPages)后,第一个参数" pages"是下一个函数的实际回调,而不是最后一个参数" cbGetFiles"它应该是(据我所知async瀑布说最后一个参数应该总是回调,在这种情况下显然不是)。

代码如下:

async.waterfall
            ([
                function(cbNumPages)
                {
                    request({
                        url: 'any-url',
                        qs: {},
                        method: 'GET',
                        headers: {
                            'Authorization' : 'any-auth'
                        }
                    }, (err, response, body) => {
                        if (!err && response.statusCode == 200)
                        {
                            var $ = cheerio.load(body);
                            var pagesList = $('ol.aui-nav').children();
                            if(pagesList.length<1)
                            {
                                var numPages = 1;
                            } else {
                                var numPages = pagesList.length-2;
                            }
                            console.log(numPages);
                            var pages = new Array(numPages),
                                total = numPages*20,
                                iterator = 0;

                            async.eachSeries(pages, function(page, cb)
                            {
                                if(page>1)
                                {
                                    pages[iterator] = iterator;
                                }else {
                                    pages[iterator] = iterator*20;
                                }
                                iterator++;
                                cb();
                            }, function(err){
                                if(err) cbNumPages(err);
                                cbNumPages(null, pages);
                            });
                        } else {
                            cbNumPages(err);
                        }
                    })
                },

                function(pages, cbGetFiles)
                {
                    var files = [];
                    var limitDate = moment().tz('Europe/Madrid').subtract(330,'days').format();

                    async.eachSeries(pages, function(page, cb)
                    {
                        request({
                            url: 'any-url'+page,
                            qs: {},
                            method: 'GET',
                            headers: {
                                'Authorization' : 'any-auth'
                            }
                        }, (err, response, body) => {
                            if(!err && response.statusCode == 200)
                            {
                                var $ = cheerio.load(body);
                                var rows = $('tr[id^=\'attachment-\']');
                                async.eachLimit(rows, 1, function(row, cb)
                                {
                                    var id = row.attribs['id'];
                                    var file = row.attribs['data-attachment-filename'];
                                    var author = $(row).children('.creator').text().trim();
                                    var created = $(row).children('.created-date').text().trim();
                                        created = moment.tz(created, 'MMM D, YYYY', 'Europe/Madrid').format();
                                    var urlFile = 'simple-file' + $(row).children('.filename-column').children('.filename').attr('href');
                                    var extension = row.attribs['data-attachment-filename'].split('.');
                                        extension = extension[extension.length-1];
                                    if(created<limitDate && validExtensions.indexOf(extension)>-1)
                                    {
                                        var f = '{ "id": "' + id + '",';
                                            f += ' "file": "' + file + '",';
                                            f += ' "url": "' + urlFile + '",';
                                            f += ' "author": "' + author + '",';
                                            f += ' "modified": "' + created + '" }';
                                        files.push(JSON.parse(f));
                                    }
                                    cb();
                                }, (err) => {
                                    if(err) cbGetFiles(err);
                                });
                                cb();
                            } else {
                                cb(err);
                            }
                        });
                    }, function(err){
                        if(err){
                            cbGetFiles(err);
                        } else {
                            cbGetFiles(null, files);
                        }
                    });
                },

                function(files, cbGetAutors)
                {
                    var filesFinal = {};
                    for(var f in files)
                    {
                        if(!filesFinal[files[f].author])
                        {
                            var ff = {};
                            for(var i in files)
                            {
                                if(files[i].author === files[f].author)
                                {
                                    ff[files[i].file] = files[i].url;
                                }
                            }
                            filesFinal[files[f].author] = ff;
                        }
                    }
                    cbGetAutors(null, JSON.parse(JSON.stringify(filesFinal)));
                },

                function(filesFinal, cbSendEmail)
                {
                    var authors = Object.keys(filesFinal);
                    async.eachSeries(authors, function(author, cb)
                    {
                        var name = author.split(' ');

                        var email = 'simple-mail@gmail.com';
                        var msg = '<p>Hi ' + author + ',</p><p>how is it going:</p><p>';
                        for(var a in Object.keys(filesFinal[author]))
                        {
                            msg += '<p style="margin-left:20px"> '+ICON_DOC+' <a href="';
                            msg += filesFinal[author][Object.keys(filesFinal[author])[a]]+'">'+Object.keys(filesFinal[author])[a]+'</a></p>';
                        }
                        msg += '</p></p><p><b>NOTE: This is a no-reply address.</b></p><p>Have a nice day! '+ICON_MONKEY+'</p>';

                        var message = {
                            text:    msg,
                            from:    'test@mail.com',
                            to:      email,
                            bcc:     '',
                            subject: 'Sample subject',
                            attachment: [{data: msg, alternative: true}]
                        };

                        serverEmail.send(message, function(err, message)
                        {
                            if(err)
                            {
                                cb(err);
                            } else {
                                console.log(message);
                                cb();
                            }
                        });

                    }, function(err){
                        if(err) cbSendEmail(err);
                        cbSendEmail();
                    });
                }

            ], (err) => {
                if(err) console.log(err);
            });

我想知道是否有办法控制这个问题,或者至少是否有其他选项可以解决这个问题。

感谢。

2 个答案:

答案 0 :(得分:2)

使用异步瀑布的更好(整洁)方式。

确保在任何回调函数之前使用return。我在代码中添加了它们。

另外,如果要嵌套eachSeries,最好为回调函数指定一个与父回调函数不同的名称。

我已将子async.series的'cb'更改为'inner_cb'

更新代码:

async.waterfall
([
    funcOne,
    funcTwo,
    funcThree,
    funcFour    
], (err) => {
    if(err) console.log(err);
});

funciton funcOne(cbNumPages) {
    request({
        url: 'any-url',
        qs: {},
        method: 'GET',
        headers: {
            'Authorization' : 'any-auth'
        }
    }, (err, response, body) => {
        if (!err && response.statusCode == 200)
        {
            var $ = cheerio.load(body);
            var pagesList = $('ol.aui-nav').children();
            if(pagesList.length<1)
            {
                var numPages = 1;
            } else {
                var numPages = pagesList.length-2;
            }
            console.log(numPages);
            var pages = new Array(numPages),
                total = numPages*20,
                iterator = 0;

            async.eachSeries(pages, function(page, cb)
            {
                if(page>1)
                {
                    pages[iterator] = iterator;
                }else {
                    pages[iterator] = iterator*20;
                }
                iterator++;
                return cb();
            }, function(err){
                if(err) return cbNumPages(err);
                return cbNumPages(null, pages);
            });
        } else {
            return cbNumPages(err);
        }
    })
}

function funcTwo(pages, cbGetFiles) {
    var files = [];
    var limitDate = moment().tz('Europe/Madrid').subtract(330,'days').format();

    async.eachSeries(pages, function(page, cb)
    {
        request({
            url: 'any-url'+page,
            qs: {},
            method: 'GET',
            headers: {
                'Authorization' : 'any-auth'
            }
        }, (err, response, body) => {
            if(!err && response.statusCode == 200)
            {
                var $ = cheerio.load(body);
                var rows = $('tr[id^=\'attachment-\']');
                async.eachLimit(rows, 1, function(row, inner_cb)
                {
                    var id = row.attribs['id'];
                    var file = row.attribs['data-attachment-filename'];
                    var author = $(row).children('.creator').text().trim();
                    var created = $(row).children('.created-date').text().trim();
                        created = moment.tz(created, 'MMM D, YYYY', 'Europe/Madrid').format();
                    var urlFile = 'simple-file' + $(row).children('.filename-column').children('.filename').attr('href');
                    var extension = row.attribs['data-attachment-filename'].split('.');
                        extension = extension[extension.length-1];
                    if(created<limitDate && validExtensions.indexOf(extension)>-1)
                    {
                        var f = '{ "id": "' + id + '",';
                            f += ' "file": "' + file + '",';
                            f += ' "url": "' + urlFile + '",';
                            f += ' "author": "' + author + '",';
                            f += ' "modified": "' + created + '" }';
                        files.push(JSON.parse(f));
                    }
                    return inner_cb();
                }, (err) => {
                    if(err) return cbGetFiles(err);
                });
                return cb();
            } else {
                return cb(err);
            }
        });
    }, function(err){
        if(err){
            return cbGetFiles(err);
        } else {
            return cbGetFiles(null, files);
        }
    });
}

function funcThree(files, cbGetAutors) {
    var filesFinal = {};
    for(var f in files)
    {
        if(!filesFinal[files[f].author])
        {
            var ff = {};
            for(var i in files)
            {
                if(files[i].author === files[f].author)
                {
                    ff[files[i].file] = files[i].url;
                }
            }
            filesFinal[files[f].author] = ff;
        }
    }
    return cbGetAutors(null, JSON.parse(JSON.stringify(filesFinal)));
}

function funcFour(filesFinal, cbSendEmail) {
    var authors = Object.keys(filesFinal);
    async.eachSeries(authors, function(author, cb)
    {
        var name = author.split(' ');

        var email = 'simple-mail@gmail.com';
        var msg = '<p>Hi ' + author + ',</p><p>how is it going:</p><p>';
        for(var a in Object.keys(filesFinal[author]))
        {
            msg += '<p style="margin-left:20px"> '+ICON_DOC+' <a href="';
            msg += filesFinal[author][Object.keys(filesFinal[author])[a]]+'">'+Object.keys(filesFinal[author])[a]+'</a></p>';
        }
        msg += '</p></p><p><b>NOTE: This is a no-reply address.</b></p><p>Have a nice day! '+ICON_MONKEY+'</p>';

        var message = {
            text:    msg,
            from:    'test@mail.com',
            to:      email,
            bcc:     '',
            subject: 'Sample subject',
            attachment: [{data: msg, alternative: true}]
        };

        serverEmail.send(message, function(err, message)
        {
            if(err)
            {
                return cb(err);
            } else {
                console.log(message);
                return cb();
            }
        });

    }, function(err){
        if(err) return cbSendEmail(err);
        return cbSendEmail();
    });
}

答案 1 :(得分:0)

正如@YSK在评论中所说的那样,我从response.statusCode中获取了一个401,因此它被误导到cbSendEmail(错误),并且错误地冒犯了null。在瀑布的第一个参数中使用下一个方法,而不是第二个参数。