在现有对象中添加新元素

时间:2014-08-19 03:44:52

标签: javascript node.js javascript-objects

我正在使用node.js。

我必须在对象中添加新元素才能向客户端发送响应。

user.getMatch(req.user, function(err, match){

        for( k=0; k<match.length; k++){
            var userId = {
                id : match[k].match_id  
            };
            var user = new User(userId);
            console.log('k: ' + k);
            user.getUserInfo(function(err2, info){
                console.log('k here: ' + k);
                if(info){
                    match[k].foo = info[0].foo;
                }
            });
        }

        var response = {
                data    : match
            };
        res.json(response);
});

我想添加一个元素&#34; foo&#34;从user.getUserInfo到对象&#34;匹配&#34; user.getMatch返回的内容。然后将所有数据作为响应发送给客户端。

但它有一个错误,因为&#34; k&#34; user.getUserInfo里面不等于&#34; k&#34;外。 我不知道为什么这两个&#34; k&#34;不平等。

如何在执行循环后向客户端发送响应。

感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

这里有一些问题:

首先,k未定义,因此您使用的k实际上是一个不是您想要的全局变量。您需要将其定义为'var k'。

其次,您传递给user.getUserInfo()的回调函数(可能)将来会在某个未知时间执行。此时,您的循环for (k ...已经完成,因此k变量已经具有一个新值,因为它在您调用user.getUserInfo()时具有的值。这里是棘手的部分:回调函数中的代码将使用k的最新值。它将使用k创建函数时的值。

您可以通过向回调函数添加参数并使用.bind方法将k绑定到它来解决此问题:

user.getMatch(req.user, function(err, match){

  var k;
  for(k=0; k < match.length; k++){
    var userId = {
      id : match[k].match_id  
    };
    var user = new User(userId);
    console.log('k: ' + k);

    var callback = function(k, err2, info){
      console.log('k here: ' + k);
      if(info){
        match[k].foo = info[0].foo;

      }
    }.bind(null, k);
    user.getUserInfo(callback);
  }

  var response = {
    data: match
  };
  res.json(response);
});

另外,使用.forEach迭代数组会更好:

user.getMatch(req.user, function(err, match){

  match.forEach(function(curr) {
    var userId = {
      id : curr.match_id  
    };
    var user = new User(userId);

    user.getUserInfo(function(err2, info){
      if(info){
        curr.foo = info[0].foo;
      }
    }
  });

  var response = {
    data: match
  };
  res.json(response);
});

虽然Array.forEach可以在迭代中为您提供当前索引,但不再需要这样。只需使用curr值(它为您提供迭代中的当前元素)。

最后,我认为此处的代码可能会在执行所有user.getUserInfo()调用之前发送响应。要实现这一点,您需要知道所有user.getUserInfo()何时完成。这可以通过添加变量numLeft来实现,该变量在每次获取用户信息时递减。当此变量达到零时,我们知道所有getUserInfo()都已完成,因此可以安全地发回响应。

user.getMatch(req.user, function(err, match) {

  var numLeft = match.length;

  match.forEach(function(curr) {
    var user = new User({
      id : curr.match_id  
    });

    user.getUserInfo(function(err2, info){
      if(info) {
        curr.foo = info[0].foo;
      }
      --numLeft;
      if (numLeft == 0)
        res.json({ data: match });
    }
  });
});

答案 1 :(得分:0)

当你说&#34; k内外&#34;你的意思是在user.getUserInfo内部和外部(函数(err2,info){})?
我不确定你的背景,但我可以想到两件事

  1. 由于功能&#34;功能(错误2,信息)&#34;是一个回调,并且异步执行getUserInfo中使用k的上下文/堆栈是完全不同的。所以尝试在呼叫时传递k,即

    user.getUserInfo(function(err2,info,k){})。这应该有用

  2. 尝试在要使用它的闭包中声明k即var k



  3. 更新另一部分问题
    &#34;但是我又遇到了另一个问题..它在添加&#34; foo&#34;之前向客户发送回复。元件。所以在对客户端的响应中,它只发送来自&#34; match&#34;没有&#34; foo&#34;元素&#34。
    这也是因为你的内部获取用户信息的ur代码是异步执行的。 为此,您需要保留全局标志或尝试从getUserInfo中发送响应 即。

    var mathLen = match.length;
    user.getUserInfo(function(err2, info,k,mathLen)
    
    {
                    console.log('k here: ' + k);
                    if(info){
                        match[k].foo = info[0].foo;
                    }
                    if(k==mathLen)
                    {
                     var response = {
                        data    : match
                    };
                res.json(response);
                         }
    
                });