1

I'm trying to add a new property to an object. It seems that it works correctly from this scope:

rows.forEach(function (row, i) {
  row.foo = i;
});

If I do console.log(rows) I can see that foo was added with the correct value. If I have another callback within the forEach, I don't see the change any more. Why?

rows.forEach(function (row, i) {
  getUserById(row.user_id, function(user) {           
    row.foo = i;
  });
});

Yes, the callback get's fired correctly. Here is the getUserById

function getUserById(userId, callback) {
  connection.query('select * from t_user where id = ?', [userId], function(err, results) {

  if (err) {
    console.log("repo error");
  } else {
    if (results.length == 0) {
      callback(null);
  } else {
      callback(results[0]);
    }
  }
});

}

user1218776
  • 439
  • 6
  • 18
  • 1
    That should work, assuming that `getUserById` calls the callback. Can you post more of your code? – robbrit Feb 08 '13 at 21:44
  • 1
    what is `getUserById`? You're defining the inner function but it's not invoked anywhere here, and if that's what you meant to do it's questionable why you'd be using alternate function definitions when the logic is the same. My guess is you're wrote the callback, but you're never actually calling it back. And why does the inner function have a parameter that isn't used? – Matt Whipple Feb 08 '13 at 21:45
  • Perhaps the callback is called later than you examine `row.foo` (say, an AJAX callback vs. right after the loop)? – John Dvorak Feb 08 '13 at 21:47

1 Answers1

0

I can only image that you would be seeing this issue if getUserById defers calling the callback function you pass it. On that assumption, your problem is a timing issue.

Each time you call getUserById and pass it a callback, you are basically saying "Call this function when you get the user for this id", and then going along with the rest of your program. That means that when console.log is called, your callbacks have not yet been called. Instead, you have to wait for all of your callbacks to finish, and then call any code that relies on the values you are setting in your callback.

The general approach to waiting for all your callbacks to finish is to craft a special callback function which will delegate to each callback and also keep track of once they've all been called.

Here is a question with an answer using the async library, which I'm a fan of (though there are a number of libraries to tackle this control flow problem).

Idiomatic way to wait for multiple callbacks in Node.js

Here's a raw JavaScript solution that is robust enough to work in the general case where not all the callbacks are the same (that is, if you wanted a different callback for each user id).

Multiple Asynchronous Callbacks - Using an array to fire function when complete

Community
  • 1
  • 1
George
  • 4,147
  • 24
  • 33