0

After update my sails (0.10-rc5),

I encountered a problem in beforeCreate function :

  beforeCreate : function(values, next){

      console.log("Called beforeCreate User ");
      console.log(values);

      if(!values.password || values.password !== values.confirmation){
          return next({
              err : ["Password doesn't match password confirmation"]
          });
      }

      bcrypt.genSalt(10, function(err, salt){
        console.log("call within bcrypt");
          if (err) return next(err);
           bcrypt.hash(values.password, salt, function(err, hash){
              if(err) return next(err);
               values.password = hash;
           });
      });

      Access.findOne()
          .where({ level : values.level })
          .exec(function(err, level){
            console.log("call within findOne");
              if(err) return next(err);
              values.level = level.id;
      });

      console.log("after");    
      console.log(values);
      next();
  } 

However, the output of the above function is as following :

Called beforeCreate User 
{ firstName: 'Quad',
  lastName: 'Doe',
  email: '11@11.com',
  password: '123456',
  confirmation: '123456',
  level: 'admin',
  id: '2fa1ba1a-ae1c-4380-9107-3c1f6e8eafb3',
  online: false }
after
{ firstName: 'Quad',
  lastName: 'Doe',
  email: '11@11.com',
  password: '123456',
  confirmation: '123456',
  level: 'admin',
  id: '2fa1ba1a-ae1c-4380-9107-3c1f6e8eafb3',
  online: false }
call within bcrypt
call within findOne

As you can see, somehow bcrypt.genSalt(.....){} and Access.findOne(...){} were not called prior to after, which is supposed to.

tebesfinwo
  • 715
  • 1
  • 6
  • 20

1 Answers1

1

What you are seeing is asynchronous code in action...

Node/Sails does not wait for your callbacks to fire before moving on to the the next task.

You need to "nest" your callbacks so that console.log("AFTER") is called within the last callback.

Take a look at async. It's designed for these types of problems.

Or...

Look into fibers

InternalFX
  • 1,475
  • 12
  • 14
  • Does that mean it can call very end **next()** and exit the function prior of the ending of other functions within itself ? – tebesfinwo May 05 '14 at 20:59
  • Exactly. You nailed it. If you are used to synchronous programming, it seems confusing at first. Fibers are really nice for making node "feel" synchronous. – InternalFX May 05 '14 at 21:00
  • Thanks @InternalFX. Beforehand, the functions within **beforeCreate** were working fine (executed before the next was called) in 0.9v Sails, I guessed that they have changed. – tebesfinwo May 05 '14 at 21:15
  • @tebesfinwo Thats pretty surprising...The asynchronous nature is built into the very core of nodejs. I would recommend one of the above libraries. Even if it worked before, there was likely a nasty bug/race condition hidden under the surface. If you do not explicitly control the flow of functions, who knows how bad that could turn out. – InternalFX May 05 '14 at 21:19
  • Indeed. Okay, I will. Thank you again. – tebesfinwo May 06 '14 at 01:17