5

mongoose (または、sequelize、または redis) クエリの非同期の性質を考えると、ビューをレンダリングする前に複数のクエリを作成する必要がある場合はどうすればよいでしょうか?

たとえばuser_id、セッションに があり、 を介してその特定のユーザーに関する情報を取得したいとしますfindOne。ただし、最近ログインしたユーザーのリストも表示する必要があります。

exports.index = function (req, res) {
    var current_user = null

    Player.find({last_logged_in : today()}).exec(function(err, players) {
        if (err) return res.render('500');

        if (req.session.user_id) {
            Player.findOne({_id : req.session.user_id}).exec(function(err, player) {
                if (err) return;
                if (player) {
                    current_user = player
                }
            })
        }

        // here, current_user isn't populated until the callback fires 
        res.render('game/index', { title: 'Battle!',
                   players: players,
                   game_is_full: (players.length >= 6),
                   current_user: current_user
        });
    });
};

最初res.renderのクエリ コールバックも同様です。findOneしかし、このユーザーを知っているかどうかを確認するためにからの応答を待つのはどうでしょうか? 条件付きでのみ呼び出されるためrender、いずれかの条件で複製しない限り、内側のコールバック内に配置することはできません。かわいくない。

私はいくつかの回避策を考えることができます -

  • 実際に非同期にし、クライアント側で AJAX を使用して現在のユーザーのプロファイルを取得します。しかし、これは価値があるよりも多くの作業のようです。

  • を使用し、レンダリングの前Qにクエリの解決を待つことを約束します。findOneしかしある意味では、これは私の操作で応答を待機させるためにブロックを強制するようなものです。正しくないようです。

  • ミドルウェア関数を使用して現在のユーザー情報を取得します。これはよりきれいに見え、クエリを再利用可能にします。ただし、どうすればよいのか、それとも同じ問題が引き続き発生するのかはわかりません。

もちろん、より極端なケースでは、作成するクエリが多数ある場合、状況が悪化する可能性があります。では、この種の要件が与えられた通常のパターンは何ですか?

4

3 に答える 3

5

はい、これは非同期コードでは特に厄介なケースです。あなたができることは、複製しなければならないコードをローカル関数に入れて、それを乾いた状態に保つことです。

exports.index = function (req, res) {
    var current_user = null

    Player.find({last_logged_in : today()}).exec(function(err, players) {
        if (err) return res.render('500');

        function render() {
            res.render('game/index', { title: 'Battle!',
                       players: players,
                       game_is_full: (players.length >= 6),
                       current_user: current_user
            });
        }

        if (req.session.user_id) {
            Player.findOne({_id : req.session.user_id}).exec(function(err, player) {
                if (err) return;
                if (player) {
                    current_user = player
                }
                render();
            })
        } else {
            render();
        }
    });
};

ただし、ここで行っていることを見ると、おそらく複数のリクエストハンドラーで現在のプレーヤー情報を調べる必要があるため、その場合はミドルウェアを使用することをお勧めします。

何かのようなもの:

exports.loadUser = function (req, res, next) {
    if (req.session.user_id) {
        Player.findOne({_id : req.session.user_id}).exec(function(err, player) {
            if (err) return;
            if (player) {
                req.player = player
            }
            next();
        })
    } else {
        next();
    }
}

次に、loadUser必要な場所に電話をかけるようにルートを構成するreq.playerと、ルートハンドラーはそこからプレーヤーの詳細を取得できます。

于 2012-11-06T03:03:15.233 に答える
0

最近では、ExpressJS で app.param を使用して、リクエスト URL のパラメーターの名前に基づいて必要なデータをロードするミドルウェアを簡単に構築できます。

http://expressjs.com/4x/api.html#app.param

于 2014-10-08T15:12:55.150 に答える