【问题标题】:Tracking when several callbacks are complete in node.js with Mongoose and FeedParser使用 Mongoose 和 FeedParser 在 node.js 中跟踪多个回调何时完成
【发布时间】:2012-03-22 03:01:24
【问题描述】:

我正在编写一个批处理来读取 RSS 提要,并通过 Mongoose 将内容存储在 MongoDB 中。我会运行脚本,它会很好地处理内容......但脚本不会返回到控制台。我的假设是我的数据库连接仍然打开,这就是我没有返回的原因。

我不能只跟踪解析完成的时间,因为我可能还有一些 mongoose 保存操作正在进行。

所以,我编写了一个函数来跟踪我打开的数据库连接,以及我的 RSS 解析状态。但是我的代码最终变得非常冗长。我想知道是否有更好的模型/模式来做这样的事情。

var FeedParser = require('feedparser')
    , mongoose = require('mongoose');

var TEST_RSS_URL = "./test/data/20120303-seattle.rss";
var OPEN_DB_CONNECTIONS = 0;
var PARSING_DONE = false;

/*
 * Keeps track of open database connections, and closes the connection when done
 */
function track_and_close_database(mode) {
    switch(mode)
    {
    case 'open':
        OPEN_DB_CONNECTIONS++;
        break;
    case 'close':
        OPEN_DB_CONNECTIONS--;
        if (0 == OPEN_DB_CONNECTIONS && PARSING_DONE) conn.close();
        break;
    case 'parseStart':
        PARSING_DONE = false;
        break;
    case 'parseEnd':
        PARSING_DONE = true;
        if (0 == OPEN_DB_CONNECTIONS && PARSING_DONE) conn.close();
        break;
    }
}

function parse_stuff(stuff) {
    // do some stuff
    setTimeout(console.log("parsed some stuff",20));
}

function main() {
    parser = new FeedParser();

    parser.on('article', function(article) {
        track_and_close_database('open');
        // check to see if we already have this listing
        stuff_model = conn.model('stuff');
        stuff = stuff_model.findOne({'href': article.link}, function (error, doc) {
            if (error) {
                track_and_close_database('close');
                return;
            }
            // this one doesn't exist yet, parse and save
            if (null == doc) {
                listing = parse_stuff(article);

                // if listing is valid, save it!
                if (null != listing) {
                    listing.save(function (error) { track_and_close_database('close') });
                }
                // parsing failed
                else track_and_close_database('close');
            }
            // nothing to do, already in the database
            else track_and_close_database('close');
        });
    });

    // Completed parsing the RSS file
    parser.on('end', function(article) {
    track_and_close_database('parseEnd');
    });

    track_and_close_database('parseStart')
    parser.parseFile(TEST_RSS_URL);
}

// run this thing
main();

【问题讨论】:

    标签: node.js mongodb asynchronous mongoose feedparser


    【解决方案1】:

    我也遇到过这个问题。我认为处理这个问题的首选方法是使用事件,但是在查看源代码时,似乎没有任何东西可以保持某种类型的操作计数。我最终将它连接到 EventEmitter。如果 Mongoose 在保存之前和之后发出事件会更好,这样我就不必将它插入到我的所有模型中。

    以下是我的做法示例:

    /* lib/render_log.js */
    /* Model for managing RenderLog */
    
    var common = require("./common");
    common.initialize_locals(global);
    
    var mongoose = require("mongoose"),
        Schema = mongoose.Schema;
    
    var RenderLogSchema = new Schema({
        renderer: String,
        template: String,
        content: {}
    });
    
    RenderLogSchema.pre('save', function(next){
      this.db.model('RenderLog').emit('open_db_op', this); 
      next();
    });
    
    RenderLogSchema.post('save', function(){
      this.db.model('RenderLog').emit('close_db_op', this); 
    });
    
    mongoose.connect('mongodb://localhost/time-jr-development');
    
    var RenderLog = mongoose.model("RenderLog", RenderLogSchema);
    exports = module.exports = RenderLog;
    

    接下来是我的测试可执行文件:

    /* bin/test_mongoose.js */
    
    var async = require('async');
    var RenderLog = require("../lib/render_log");
    
    var ConnectionManager = {
      open_db_ops: 0,
    
      new_db_op: function(){
            this.open_db_ops ++;
      },
    
      close_db_op: function(){
        this.open_db_ops --;
      },
    
      close: function(self){
            if(!self)
          self = this;
        if(self.open_db_ops > 0){
          console.log("Waiting...")
          process.nextTick(async.apply(self.close, self));
        }else{
          RenderLog.db.close();
        }
      }
    };
    
    
    RenderLog.on("open_db_op", function(model){
      ConnectionManager.new_db_op();
    });
    
    RenderLog.on("close_db_op", function(model){
      ConnectionManager.close_db_op();
    })
    
    new RenderLog({renderer: "foo", template: "foo.html", content: {"bar": 1}}).save();
    new RenderLog({renderer: "foo", template: "foo.html", content: {"bar": 2}}).save();
    new RenderLog({renderer: "foo", template: "foo.html", content: {"bar": 3}}).save();
    new RenderLog({renderer: "foo", template: "foo.html", content: {"bar": 4}}).save();
    new RenderLog({renderer: "foo", template: "foo.html", content: {"bar": 5}}).save();
    // You have to push this to the next tick otherwise it gets called before the save
    // events have been emitted
    async.nextTick(async.apply(ConnectionManager.close, ConnectionManager));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-09-05
      • 2014-11-02
      • 1970-01-01
      • 2014-11-19
      • 2022-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多