1

サーバーサイドコーディングにNode.jsとExpressjsを使用し、バックエンドとしてMongoDBを使用しています。私はこれらすべてのテクノロジーに不慣れです。リクエストに基づいてアクションのリストを作成する必要があります。

たとえば、ユーザー管理で

  1. すでに登録されているユーザーを確認してください
  2. 登録されている場合は、アクティベーションメールを再送信してください
  3. 登録されていない場合は、ユーザー、アセットなどのIDを維持する別のテーブルからuserIdを取得します。[MongoDBが一意の_idを提供することはわかっています。しかし、userIdとして一意の整数IDが必要です]
  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);
    }
}

そして同様に他の機能。

register関数の最初の呼び出しは、app.getから実行されます。

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

これを行うためのより良い方法はありますか?私が直面している問題は、一連の行動に従わなければならないいくつかの条件に基づいています。これらすべてをネストされたコールバック構造で記述できますが、その場合、コードを再利用することはできません。

上司が私に言った問題の1つは、コードで関数レジスタを呼び出して、コールバックのスタックに次のように配置することでした。

状態1:chekuser

状態3:getIds

状態4:ユーザーの作成

そして最後に状態200になり、ここでスタックを終了しますか?スタックオーバーフローを引き起こす可能性があります!

Node.js / Expressjsでコールバックを処理するためのより良い方法はありますか?

注:上記はサンプルコードです。このようなさまざまな状況があります。

4

2 に答える 2

3

おそらく、よりエレガントな方法は、考えられるさまざまな関数をすべて1つのオブジェクトにまとめて、現在の状態に基づいて必要なものを呼び出すことです。

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

次に、すべてを実行する1つの関数が必要です

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

このようにして、ステップのリストが素晴らしく、読みやすく、変更可能になります。すべてを実行する1つの関数があり、各ステップは次のステップがどうあるべきかを管理する必要があります。必要に応じて、番号付きのステップを名前付きに置き換えることもできます。これにより、読みやすくなりますが、ステップ変数をインクリメント/デクリメントすることはできなくなります。

于 2012-12-23T07:26:44.527 に答える
2

ここでは、ミドルウェア、データベースレイヤー、ルートハンドラーを組み合わせてオーバーエンジニアリングしています。よりシンプルで再利用しやすいものにしましょう。

まず、ミドルウェアとルートハンドラーが相互に通信できることを確認しましょう。これは、セッションミドルウェアで実現できます。

// 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からdbをクエリすることで、ユーザーが登録されているかどうかを検出するとします。

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

リクエストハンドラーは、この2つの関数内で何が起こっているか(dbクエリの数、電子メールの送信者と方法)を気にする必要はありません。エラーが発生した場合、提供されたコールバックの最初の引数はnullではないことがわかっています。

次に、新しいユーザーの作成について説明します。registerUserIDを使用してテーブルをクエリし、ユーザー情報を準備してDBに保存する関数を記述します。この2つの操作を同期する方法については、非同期およびその他のSOの質問を参照してください。作成が完了またはエラーになった場合はcallback、結果を呼び出します。この関数はDBレイヤーの一部である必要があります。少なくとも、モジュールを作成し、;db.jsのような重要なものをエクスポートします。registerUser電子メール(最初のミドルウェア内)によるユーザー情報のクエリも、DBレイヤー内に存在する必要があります。

同様のことが。にも当てはまりますsendActivationEmail

補足_id: mongo documetには、だけでなく、好きなものを入れることができますObjectId

于 2012-12-23T19:34:44.453 に答える