我使用Node.js和Expressjs作为服务器端编码,使用MongoDB作为后端。我是所有这些技术的新手。 我需要根据请求做一系列操作。
例如在用户管理中
为了实现这一点,我编写了以下代码:
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);
}
}
与其他功能类似。
第一次调用register函数将从app.get执行
user.register(req,res,1,this,function(status) {
//do somthing
});
有没有更好的方法呢?我面临的问题是基于一些条件我必须遵循一系列行动。我可以在嵌套的回调结构中编写所有这些,但在这种情况下,我无法重用我的代码。
我的老板告诉我的一个问题是,我在代码中调用函数寄存器并将其放入一堆回调中
州1:chekuser
州3:getIds
状态4:创建用户
最后在200州,我刚从堆栈退出?它可能导致堆栈溢出!
有没有更好的方法来处理Node.js / Expressjs中的回调?
注意:上面是一个示例代码。我有很多不同的情况。
答案 0 :(得分: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)
}
你的每个函数都只是将state参数设置为它需要的东西,然后召回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替换带编号的步骤,这样可以使其更具可读性,但是您将无法增加/减少步进变量。
答案 1 :(得分: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();
});
您现在想要的是在请求处理期间将用户信息放在任何地方。现在,它只是电子邮件,是否注册。那将是第一个独立的中间件。为简洁起见,我们假设您通过query string的email
查询数据库来检测用户是否已注册。
// 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);
});
});
请求处理程序不应该被这两个函数内部发生的事情所困扰(有多少数据库查询,谁在发送电子邮件以及如何发送)。它只知道如果发生错误,提供的回调的第一个参数不为空。
现在关于创建新用户。编写registerUser
函数,该函数将使用ID查询表,在DB中准备并保存用户信息。有关如何同步这两项操作,请参阅async和其他SO questions。创建完成或出错后,请使用结果调用callback
。此功能应该是DB层的一部分。至少,创建db.js
模块并导出重要内容,例如registerUser
;通过电子邮件(在第一个中间件内部)查询用户信息也应该存在于DB层内。
类似适用于sendActivationEmail
。