joshula
joshula

Reputation: 555

Async Patterns with Node.js and Mongoose

Specifically I'm working with Mongoose and Node, but I guess this is a more conceptual question about asynchronous coding.

I see this example all over Mongoose docs:

product.sold = Date.now();
product.save(function (err, product, numberAffected) {
  if (err) ..
})

However, what if

product.save(...) 

executes faster than

product.sold = Date.now()

Wouldn't you be saving before updating...? Maybe I'm missing something here (at a conceptual level)? What's keeping this code "safe" in an asynchronous environment.

More specifically I'm using doc.addToSet as the "update" step, and I'd feel much better if it had a callback I could embed the doc.save step in (to ensure async behavior). Thoughts?

PS. I'm not simply using model.update because I need validation.

Upvotes: 0

Views: 351

Answers (2)

mexezero
mexezero

Reputation: 21

Asynchronous doesn't mean each line gets executed simultaneously. In this case product.sold is getting assigned and finishes like a normal operation, then save is getting called sequentially afterwards.

The asynchronous part happens with product.save. What is happening is you are passing a function as an argument to product.save which is also a function. This is called an anonymous callback. It does not have a name and gets called asynchronously from inside product.save.

Here is how execution would be ordered:

  1. Date.now() gets assigned to product.sold and the operation finishes
  2. product.save(callback(...){...}) gets called
  3. product.save reaches the callback and executes it, i.e. there is a line in the definition of product.save that says callback.call(...), then product.save returns
  4. Execution continues with the next line after product.save (which you haven't listed) but before the callback finishes
  5. The callback finishes sometime

So you update product and save it successfully. The anonymous function you pass is not what actually saves it but rather an asynchronous extension to do what you want, i.e. process errors or make sure the correct number of items get saved.

Upvotes: 1

ploutch
ploutch

Reputation: 1214

You don't have to worry about the update operation to happen before the save, because it is blocking.

To understand what the difference is between a blocking (synchronous) and non-blocking (asynchronous) operation, take this basic asynchronous code :

function async(callback) {
  process.nextTick(callback);
}

async(function() {
  console.log('foo');
}
console.log('bar');

This will display in order bar, then foo. The key here is the function process.nextTick(cb), which will delay the execution of the callback.

Since NodeJS uses only one thread, it will wait for the whole stack of functions to return, then execute the callback in the next loop of the process. Now, if your update operation was asynchronous, you would have to do your save operation in the callback function passed to that operation.

However, since it is not (you can see that from the doc, and generally, the fact that the function is not accepting any callback parameter is a good indication), the execution of the function will be blocked until that update operation returns.

Upvotes: 0

Related Questions