Reputation: 13206
I am wondering what happens to a javascript object that is passed to an asynchronous function (like a database save), and then immediately has its property's value changed.
The reason I am interested in this is that the asynchronous code takes a long time to finish and so waiting for it to callback would take longer than I would like to respond.
Take the following code:
function asyncDatabaseSave(user) {
// Save the user asynchronously in the database
// Do things that take a lot of time before calling back
}
app.get(function (req, res) {
// In real code user is an object that gets passed in.
user = {cart: [1, 2, 3]};
// What is the value of user.cart going to be when it reaches the databaseSave call?
// At the time of the function call, user.cart has options but it is set to null immediately after
asyncDatabaseSave(user);
user.cart = null;
res.json(user);
})
I think that the "correct" way to ensure that the user object was saved with the cart not null
and then clear it would be to pass a callback into asyncDatabaseSave
to set it to null
after the save.
However I am interested in calling res.json
as soon as possible. I have also experimented with this code:
app.get(function (req, res) {
var items = user.cart;
user.cart = null;
res.json(user);
asyncDatabaseSave(user, items);
})
This way items
is stored as a separate var and passed into a slightly-modified database save function.
What happens to user.cart
when asyncDatabaseSave
is called and then it is set to null
immediately after?
If I am trying to save user
with cart, but also return the user
with cart set to null
what is the best way to do this?
Upvotes: 2
Views: 56
Reputation: 707716
What happens to user.cart when asyncDatabaseSave is called and then it is set to null immediately after?
You'd have to know what actually happens in the async database call to know whether it's safe to modify the passed in object immediately after making the call or not. There are many cases where the operative parts of the user
object would already be copied into native code and sent off to the database before asyncDatabaseSave()
returns so further modifying the user
object would not affect the async call at all.
But, there are situations where you can't assume that, particular if asyncDatabaseSave()
is actually made up of several async calls and some Javascript runs between them (such as opening the db, then writing to the db. In those cases, modifying the user
object where you are could affect things.
If I am trying to save user with cart, but also return the user with cart set to null what is the best way to do this?
So, to be safe, don't modify the user
object right after asyncDatabaseSave(user)
.
If you really just want to call res.json(user)
as fast as possible, then you can just make a copy of the user
object, modify that copy and then use each separate copy in your two async operations. That's the general answer that works in all cases and it's the safe way to do things.
If the whole cart
object is not needed in asyncDatabaseSave()
, then picking out just the parts that are needed and passing those (like your last suggestion), allows you to freely assign cart
properties afterwards without any risk. You do have to be careful that you aren't reaching into the cart
object and changing objects in the cart
object because that might be changing the same objects that you passed to asyncDatabaseSave()
, but you can certainly assign properties to the cart
object and that will not affect asyncDatabaseSave()
if you didn't pass it the cart
object.
Here's a simple example to show how it's not safe to assume you can modify the object you passed in:
function someAsyncSave(u) {
setTimeout(function() {
log(u.name)
}, 50);
}
var user = {name: "Joe"};
someAsyncSave(user);
user.name = "Alice";
<script src="http://files.the-friend-family.com/log.js"></script>
Run the snippet. It will log "Alice", even though the property was "Joe" when someAsyncSave()
was called.
Even though the user
object had user.name = "Joe"
when it was passed to someAsyncSave()
, by the time someAsyncSave()
actually uses the property, it has already been changed by the outer code.
Upvotes: 3