14

私は現在、nodeJs、expressJs、MongoDB、html5、...を使用して、3人の友人とプロジェクトに取り組んでいます。これらのテクノロジーはかなり新しいので、いくつかの問題にぶつかりました。解決策が見つからない大きな問題は、特定のコードの非同期実行です。

for eachループを終了して、更新されたオンラインフレンドリストを作成し、res.render(オンラインフレンドリストを渡す)を実行します。これは、現在、ループが終了する前にres.renderを実行するためです。 。コード:

function onlineFriends(req, res) {
var onlinefriends = new Array();
onlinefriends.push("mark");
FriendList.findOne({
    owner: req.session.username
}, function (err, friendlist) {
    friendlist.friends.forEach(function (friend) { // here forEach starts
        OnlineUser.findOne({
            userName: friend
        }, function (err, onlineFriend) {
            if (onlineFriend != null) {
                onlinefriends.push(onlineFriend.userName);
                console.log("a loop");
            }
        });

    });  
        console.log("online friends: " + onlinefriends);
        console.log("redirecting");
        res.render('index', { // this is still inside the forEach function
            friendlist: friendlist.friends,
            onlinefriendlist: onlinefriends,
            username: req.session.username
        });// and here it ends
});

}

出力は次のようになります。

online friends: mark
redirecting
a loop
a loop
a loop
a loop
a loop
a loop
a loop

ここで説明したように(JavaScript、Node.js:Array.forEachは非同期ですか?)、答えはfor-eachがブロックしているということですが、私の例では、res.renderを実行する前に実行するため、ブロックされていないようです。ループが終了しましたか?for eachが終了する前にres.renderが発生する代わりに、res.renderに渡すことができる最新のオンラインフレンドリスト(およびフレンドリスト)を取得できるように、foreachが終了していることを確認するにはどうすればよいですか(これは私にオンラインユーザーの間違ったリストを与えます)?

どうもありがとう!

4

3 に答える 3

15

次のコンソールログ:

console.log("a loop");

コールバック内にあります

関数OnlineUser.findOne()のコールバックは非同期で呼び出されると思います。そのため、コードはリダイレクトログの後に「ループ」をログに記録します。

すべてのループコールバックが実行された後にリダイレクトを配置する必要があります

何かのようなもの:

var count = 0;
friendlist.friends.forEach(function (friend) { // here forEach starts
    OnlineUser.findOne({
        userName: friend
    }, function (err, onlineFriend) {
        count++;
        if (onlineFriend != null) {
            onlinefriends.push(onlineFriend.userName);
            console.log("a loop");
        }
        if(count == friendlist.friends.length) { // check if all callbacks have been called
            redirect();
        }
    });
}); 

function redirect() {
    console.log("online friends: " + onlinefriends);
    console.log("redirecting");
    res.render('index', { // this is still inside the forEach function
        friendlist: friendlist.friends,
        onlinefriendlist: onlinefriends,
            username: req.session.username
    });// and here it ends
}
于 2012-05-14T08:36:47.447 に答える
6

プロジェクトにasyncパッケージを追加し、forEach()をasync.each( )に変更することで、同様の問題を解決することができました。利点は、これがアプリケーションの他の部分の同期を行うための標準的な方法を提供することです。

あなたのプロジェクトのためにこのようなもの:

function onlineFriends(req, res) {
  var onlinefriends = new Array();
  onlinefriends.push("mark");

  FriendList.findOne({owner: req.session.username}, function (err, friendlist) {
    async.each(friendlist.friends, function(friend, callback) {
      OnlineUser.findOne({userName: friend}, function (err, onlineFriend) {
        if (onlineFriend != null) {
          onlinefriends.push(onlineFriend.userName);
          console.log("a loop");
        }
        callback();
      });
    }, function(err) {
      console.log("online friends: " + onlinefriends);
      console.log("redirecting");
      res.render('index', { // this is still inside the forEach function
          friendlist: friendlist.friends,
          onlinefriendlist: onlinefriends,
          username: req.session.username
      });
    });
  });
}
于 2014-03-31T02:38:37.953 に答える
2

jsbeautifierを介してコードを実行すると、コードが適切にインデントされ、その理由が示されます。

function onlineFriends(req, res) {
    var onlinefriends = new Array();
    onlinefriends.push("mark");
    FriendList.findOne({
        owner: req.session.username
    }, function (err, friendlist) {
        friendlist.friends.forEach(function (friend) { // here forEach starts
            console.log("vriend: " + friend);
            OnlineUser.findOne({
                userName: friend
            }, function (err, onlineFriend) {
                if (onlineFriend != null) {
                    onlinefriends.push(onlineFriend.userName);
                    console.log("online friends: " + onlinefriends);
                }
            });
            console.log("nu door verwijzen");
            res.render('index', { // this is still inside the forEach function
                friendlist: friendlist.friends,
                onlinefriendlist: onlinefriends,
                username: req.session.username
            });
        });  // and here it ends
    });

したがって...常にコードを適切にインデントすれば、このような問題は発生しません。gg=GVimなどの一部のエディターは、単一のショートカット( vim内)でファイル全体をインデントできます。

ただし、OnlineUser.findOne()ほとんどの場合非同期です。そのため、通話を正しい場所に移動しても機能しません。これを解決する方法については、 ShadowCloudの回答を参照してください。

于 2012-05-14T07:58:11.223 に答える