使用Mongoose和FeedParser在node.js中完成多个callback时跟踪

我正在编写一个批处理过程来读取RSS源,并通过Mongoose将内容存储在MongoDB中。 我会运行脚本,它会处理的内容就好了…但脚本不会返回到控制台。 我的假设是,我的数据库连接仍然是开放的,这就是为什么我没有返回。

我不能跟踪我的parsing完成时,因为我仍然可能有一些mongoose保存操作正在进行。

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

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(); 

我也遇到了这个问题。 我认为处理这个问题的首选方法是使用事件,但是在查看源代码时,似乎没有任何东西可以保持某种types的操作。 我结束了连接到一个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; 

跟着我的testing可执行文件:

 /* 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));