2012-12-23 52 views
1

我使用Node.js和Expressjs作为服务器端编码,MongoDB作为后端。我对所有这些技术都很陌生。 我需要根据请求执行一系列操作。有没有更好的方法来处理Node.js/Expressjs中的嵌套回调?

例如,在用户管理

  1. 检查用户已经注册
  2. 如果注册重发激活邮件
  3. 如果没有登记,然后从另一个表将保持IDS对用户获取用户标识,资产等。[我知道MongoDB提供独特的_id;但我需要一个唯一的整数ID为userId]
  4. 创建用户
  5. 发送成功或失败响应。

要实现这一点,我写了下面的代码:

exports.register = function(req,res,state,_this,callback) { 
    switch(state) { 
    case 1: //check user already registered or not 
     _this.checkUser(req, res, (state + 1), _this, _this.register, callback); 
     break; 
    case 2: //Already registered user so resend the activation email 
     _this.resendEmail(req, res, 200, _this, _this.register, callback); 
     break; 
    case 3: //not registered user so get the userId from another table that will maintain the ids for user,assets etc 
     _this.getSysIds(req, res, (state + 2), _this, _this.register, callback); 
     break; 
    case 4: //create the entry in user table 
     _this.createUser(req, res, (state + 1), _this, _this.register, callback); 
     break; 
    case 200: //Create Success Response 
     callback(true); 
     break; 
    case 101://Error 
     callback(false); 
     break; 
    default: 
     callback(false); 
    break; 
    } 
}; 

校验用户代码是这样的

exports.checkUser = function(req,res,state,_this,next,callback) { 
    //check user already registered or not 
    if(user) {//Already registered user so resend the activation email 
     next(req,res,state,_this,callback); 
    } 
    else {//not registered user so get the userId 
     next(req,res,(state + 1),_this,callback); 
    } 
} 

,类似地等功能。

寄存器函数的第一次调用将从app.get做的

user.register(req,res,1,this,function(status) { 
//do somthing 
}); 

有没有什么更好的方法来做到这一点?我面临的问题是基于一些条件,我必须遵循一系列的行动。我可以将所有这些写入嵌套的回调结构中,但在这种情况下,我无法重用我的代码。

一个问题,我的老板告诉我的是,在代码中我打电话的功能寄存器,并把它放在回调的堆栈

状态1:chekuser

状态3:getIds

状态4:创建用户

最后在状态200,这里我只是退出堆栈?它可能会导致堆栈溢出!

有没有更好的方法来处理Node.js/Expressjs中的回调?

注意:以上是一个示例code.I有这样的许多不同的情况。

回答

3

也许一个更优雅的方式就是将所有各种可能的功能放到一个对象中,然后根据你所处的状态调用你需要的任何一个对象。有点像

var States = { 
    1: checkuser, 
    2: resendEmail, 
    3: getSysIds, 
    4: createUser, 
    5: whateverIsNext 
} 

然后,你就必须有一个功能,做一切

function exec(req,res,state,_this,callback){ 
    States[state].apply(this, arguments) 
} 

而且每个函数将只设置为任何它需要的是国家的说法,再回想EXEC,例如

function checkUser(req,res,state,_this,callback){ 
    var doneRight = do_whatever_you_need; 
    state = doneRight? state++: state; //just set state to whatever number it should be 
    exec(req,res,state,_this,callback); 
} 

这样你就可以得到你的步骤清单,并且可读/可更改。你有一个执行所有事情的函数,每一步都需要管理下一步应该做什么。如果你想要的话,你也可以用named来替换已编号的步骤,这会使它更具可读性,但是你将失去增加/减少步长变量的能力。

+0

性能怎么样?这是一种很好的编码方式吗? – Damodaran

+1

从我的理解来看,这是一种非常高性能的编码方式,因为node.js是非阻塞的。函数A在函数B执行完成时执行。如果函数A是需要2秒才能完成的数据库调用,那么服务器只会继续执行其他操作,直到A完成。似乎是一种很好的编码方式。 – hobberwickey

2

您在这里过度工作混合中间件,数据库层和路由处理程序。让我们更简单,更可重用。

首先,让我们确定,我们的中间件和路由处理程序可以相互通信。这可能与session middleware来完成:

// Somewhere inside configuration: 
app.use(express.cookieParser() 
app.use(express.session({secret: 'cookie monster')); 

// If you don't want sessions, change with this: 
app.use(function (req, res, next) { 
    req.session = {}; 
    next(); 
}); 

你现在需要的是有请求处理过程中无处不在用户信息。目前,这只是电子邮件,是否注册。那将是第一个独立的中间件。为简洁起见,假设您通过查询db emailquery string来检测用户是否注册。

// Fills `req.session.user` with user info (email, registration). 
function userInfo (req, res, next) { 
    var user = req.session.user = req.session.user || {}; 
    user.email = req.query.email; // I'll skip validation. 

    // I'm not sure which mongo driver you are using, so this is more of a pseudo-code. 
    db.users.findOne({email: user.email}, function(err, bson) { 
    if (err) { 
     return next(err); // Express 3 will figure that error occured 
         // and will pass control to error handler: 
         // http://expressjs.com/guide.html#error-handling 
    } 

    // Could remember information from DB, but we'll just set `registred` field. 
    user.registred = !!bson; 
    next(); 
    }); 
} 

确定注册状态后您应该发送电子邮件或创建新的用户,这将是请求处理程序(最后参数有关app.get)。此前执行的处理程序,我们希望我们的userInfo运行(可以通过只是userInfo(不是数组),但我个人比较喜欢这种方式更多):

app.get('/register', [userInfo], function (req, res) { 
    var user = req.session.user; 
    var fn = user.registred ? sendActivationEmail 
          : registerUser; 

    // If signatures differs or you need different reply for cases... 
    // Well, you'll figure. 
    fn(user.email, function (err) { 
    return res.send(err ? 500 : 200); 
    }); 
}); 

请求处理程序不应该发生了什么这两个函数里面被人打扰(多少分贝查询,谁在发送电子邮件以及如何)。它所知道的是,如果发生错误,则提供的回调的第一个参数不为null。

现在关于创建新用户。编写registerUser函数,它将查询带有ID的表,在DB中准备并保存用户信息。有关如何同步这两个操作,请参阅async和其他SO questions。创建完成或出错时,请致电callback并附带结果。这个函数应该是DB层的一部分。至少,创建db.js模块并导出重要的东西,如registerUser;通过电子邮件查询用户信息(在第一个中间件内)也应该存在于DB层。

同样适用于sendActivationEmail

旁注:你可以把任何你想要的内_id在蒙戈documet,不只是ObjectId

相关问题