0

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.

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the response. So, is it okay because the 'update' (product.sold) is simply an assignment, and not a function? What if 'update' was a time-consuming function, would you be in danger of 'save' (product.save) running before (product.sold) finished? In my specific use-case, the 'update' is actually a function doc.addToSet.
I think that the issue isn't if the function is time consuming or not. What you need to take into account is the way how the function behaves, i.e. does it returns after doing all that is it intended to do? or does it return before doing everything and relying on a handler (or callback) to process the result of all the code of the function?
For example, let's say that you're in a restaurant asking for an order. In the end, you expect to have what you ordered, but the way it is prepared may differ on each restaurant. So, let's suppose that in restaurant_Foo, somebody takes your order, then goes to the kitchen, prepares the food, and then brings it to you, before taking another order; that is synchronous behaviour (like product.sold = Date.now()). But if instead, in restaurant_Boo all orders are taken and then the people waits for the food to be ready (like in most restaurants), that can be called asynchronous
0

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.

1 Comment

That makes sense. So, I'll be blocking the event loop, but it's probably not a huge deal since there's no I/O going on.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.