简体   繁体   中英

Add new element in existing object

I am using node.js.

I have to add new elements in the object before to send a response to client.

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

I want to add an element "foo" from user.getUserInfo to the object "match" that was returned by user.getMatch. And then send all the data as response to the client.

But it got an error because "k" inside of user.getUserInfo is not equal to the "k" outside. I do not know why the both "k" are not equal.

And how will I send a response to the client after performing the loop.

Thanks for your help!

Some problems here:

First, k is not defined so the k you're using is actually a global variable which is not what you want. You need to define it as 'var k'.

Second, the callback function you're passing to user.getUserInfo() is (probably) executed at some unknown time in the future. At this point your loop for (k ... has already finished so the the k variable already has a new value since the value that it had when you called user.getUserInfo() . And here's the tricky part: the code inside your callback function will use k's most recent value. It will not use the value that k had when the function was created.

You can solve this by adding a parameter to your callback function and binding k to it using the .bind method:

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

Also, you'd be better off by using .forEach for iterating over an array:

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

Although Array.forEach can give you your current index in the iteration, this is no longer needed. simply use the curr value (which gives you the current element in the iteration).

Finally, I think the code here is likely to send the response before all user.getUserInfo() calls have been executed. To achieve that you need to know when all user.getUserInfo() have been completed. This can be achieved by adding a variable numLeft which is decremented each time we get a user info. when this variable reaches zero we know that all getUserInfo() have completed and it is therefore safe to send the response back.

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

When you say "k inside and outside" do you mean inside and outside ofuser.getUserInfo(function(err2, info){})?
I am not sure of your context however i can think of two things

  1. Since the function "function(err2, info)" is a callback and is executed asynchronously the context/stack in which k is used within getUserInfo is completely different. So try to pass k while calling ie

    user.getUserInfo(function(err2, info, k){}). This should work

  2. Try to declare k ie var k in the closure that you want it to be used



Updating for another part of question
"But I got another issue.. it sends a response to client before it adds the "foo" element. So in the response to client, it only sends the object from "match" without the "foo" element."
That is again because ur code inside get user info gets executed asynchronously. For this you need to keep a global flag or try to send the response from within getUserInfo ie

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

            });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM