[英]Node.js - Better way to manage javascript scopes between callbacks?
[英]Is there any better way to handle the nested callbacks in Node.js/Expressjs?
我將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中的回調?
注意:以上是示例代碼,我有很多類似的情況。
也許更優雅的方法是將所有各種可能的函數放到一個對象中,然后根據所處的狀態調用所需的任何一個。
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,這將使其更具可讀性,但是您將失去增加/減少步驟變量的能力。
您在這里過度設計,混合了中間件,數據庫層和路由處理程序。 讓我們使其更簡單,更可重用。
首先,請確保我們的中間件和路由處理程序可以相互通信。 這可以通過會話中間件來實現:
// 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();
});
您現在想要的是在請求處理期間到處都有用戶信息。 現在,它只是電子郵件以及是否已注冊。 那將是第一個獨立的中間件。 為簡便起見,我們假設您通過使用來自查詢字符串的 email
查詢數據庫來檢測用戶是否已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);
});
});
請求處理程序不應被這兩個函數內部的內容所困擾(有多少數據庫查詢,誰在發送電子郵件以及如何發送)。 它所知道的是,如果發生錯誤,則提供的回調的第一個參數不為null。
現在開始創建新用戶。 編寫registerUser
函數,該函數將查詢具有ID的表,准備用戶信息並將其保存在DB中。 有關如何同步這兩個操作的信息,請參見async和其他SO問題 。 創建完成或出錯時,調用帶有結果的callback
。 此功能應該是數據庫層的一部分。 至少,創建db.js
模塊並導出重要的東西,例如registerUser
; 通過電子郵件查詢用戶信息(在第一個中間件中)也應該存在於DB層中。
類似的適用於sendActivationEmail
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.