Brian Bauer Brian Bauer - 5 months ago 27
Node.js Question

NodeJS is asynchronous and my code doesn't run in the order I am expecting

postRegistrationHandler: function (account, req, res, next) {
console.log('postRegistrationHandler activated');
account.getCustomData(function(err, data) {
if (err) {
console.log(err.toString, "error string");
return next(err);
} else {
data.mongo_id = userCreationCtrl(account);
data.save();
next();
}
});
},


This function almost works properly, but the line:

data.save();


runs before the previous line finishes which means that the data I want to save isn't present at the appropriate time.

data.mongo_id = userCreationCtrl(account);


This line calls a function that creates a mongoDB document with information in the account object and then returns the _id (which is what I am trying to save.

I thought maybe using a .then() would help but that seems to be unavailable here for some reason. If anyone sees something I'm missing, that would be quite helpful. Thank you!

Here is the userCreationCtrl file as requested:

var UserSchema = require('./../models/UserModel.js');

var createNewUser = function (account, res, next){
// We will return mongoId after it is created by submitting a newUser
var mongoId = "";
// Save StormpathID (last 22 characters of account.href property)
var newStormpathId = account.href.slice(account.href.length - 22);
console.log('stormpath ID:', newStormpathId, 'just registered!');
console.log(account);
// Create new user from model by recycling info from the Stormpath registration form and include the stormpathId as well.
var newUser = new UserSchema({
stormpathId: newStormpathId,
firstName: account.givenName,
lastName: account.surname,
email: account.email,
street: account.street,
city: account.city,
zip: account.zip
});
// This saves the user we just created in MongoDB
newUser.save(function(err, result){
console.log(result);
if (err) {
console.error(err);
}
else {
console.log("User created in MongoDB, attempting to return mongoDB _id to stormpath customData");
// Keep track of the new user's mongo _id so we can return it to the previous function and save it as Stormpath custom data.
mongoId = result._id;
console.log(mongoId, "mongoid");
return result._id;
}
});
};

module.exports = createNewUser;

Answer

You have userCreationCtrl expecting 3 arguments, account, res, and next. next is the callback that should be called after the user is created so instead of return result._id you should call next like so:

// inside of createNewUser()
newUser.save(function(err, result){
  console.log(result);
  if (err) {
    console.error(err);
  }
  else {
    console.log("User created in MongoDB, attempting to return mongoDB _id to stormpath customData");
    // Keep track of the new user's mongo _id so we can return it to the previous function and save it as Stormpath custom data.
    mongoId = result._id;
    console.log(mongoId, "mongoid");

    // IMPORTANT change to make it all work...
    // get rid of return result._id because its not doing anything
    // pass the value to your callback function instead of returning the value
    next(null, result._id);
  }
});

then calling code in postRegistrationHandler should look like this:

account.getCustomData(function(err, data) {
  if (err) {
    console.log(err.toString, "error string");
    return next(err);
  } else {
    // pass in a callback as the 3rd parameter that will be called by newUser.save() when its finished
    userCreationCtrl(account, null, function(err, resultId) {
      data.save();
      next();
    });
  }
});
Comments