javascript - node.js async.each callback, hur vet jag när det är klart?


Jag försöker förstå Node.js och vissa asynkrona operationer. I följande kod hämtar jag några RSS-flöden och sparar de artiklar som hittas om jag inte har sparat dem tidigare. Koden fungerar och sparar nya artiklar. Dock är jag inte säker på hur jag ska ändra detta så att jag vet när alla artiklar är färdigparsat. Till exempel anropas callback-funktionen på varje async.eachLimit varje gång gränsen är nådd (efter 10 artiklar eller 5 flöden). Så hur vet jag när de är färdiga?

var FeedParser = require('feedparser');
var request = require('request');
var mysql = require('mysql');
var async = require('async');

var connection = mysql.createConnection({
        host :  'localhost',
        user : 'someuser',
        password : 'somepass',
        database : 'somedb'
});

connection.connect();

connection.query('SELECT * FROM rssfeed', function(err, rows, fields) {
        if(err == null){
                async.eachLimit(rows, 5, parseFeed, function(err) {
                        if(! err) {
                                //horray
                        } else {
                                console.log(err);
                        }
                });
        }
});

function parseFeed(feed, callback) {
        var articles = [];
        request(feed.link)
        .pipe(new FeedParser())
        .on('error', function(error) {
                callback(error);
        })
        .on('meta', function(meta) {
        })
        .on('readable', function() {
                var stream = this, item;
                item = stream.read();
                if(item != null) {
                        item.rssfeed_id = feed.id;
                        articles.push(item);
                }
        })
        .on('finish', function() {
                async.eachLimit(articles, 10, parseArticle, function(err) {
                        if(! err) {
                                console.log('article each callback');
                        } else {
                                callback(error);
                        }
                });
        });
        callback();
}
function parseArticle(item, callback) {
        if(item.hasOwnProperty('rssfeed_id') && item.hasOwnProperty('guid') && item.hasOwnProperty('link') && item.hasOwnProperty('title')){
                connection.query('SELECT * FROM rssarticle WHERE rssfeed_id = ? AND guid = ?', [item.rssfeed_id, item.guid], function(err, rows, fields) {
                        if(rows.length == 0){
                                connection.query('INSERT INTO rssarticle SET ?', {
                                        rssfeed_id: item.rssfeed_id,
                                        link: item.link,
                                        title: item.title,
                                        description: item.description,
                                        publish_date: item.pubDate,
                                        guid: item.guid
                                }, function(err, result){
                                        if(err != null){
                                                console.log(err);
                                        }
                                });
                        }
                });
        }
        callback();
}

Svar #1

För det första kallar du dina återanrop för tidigt i förväg.

function parseFeed(feed, callback) {
  request
    .streamStuff()
    .streamStuff()
    .streamStuff();

  callback();
}

Du borde inte anropa callback innan du är klar. Annars kommer din "finished"-metod att anropas men din asynkrona kod kommer i själva verket fortfarande att köras.

Så istället för att göra:

.on('finish', function() {
    async.eachLimit(articles, 10, parseArticle, function(err) {
        if(! err) {
            console.log('article each callback');
        } else {
            callback(error);
        }
    });
});
callback();

Bara gör

.on('finish', function() {
    async.eachLimit(articles, 10, parseArticle, function(err) {
        if(! err) {
            // assuming this is a stub and really ends up doing `callback();`
            console.log('article each callback');
        } else {
            callback(error);
        }
    });
});