Startec
Startec

Reputation: 13206

How does asynchronous programming affect objects' properties

I have a user object that looks like this:

{
   name: "john",
   cart: [1, 2, 3]
}

This object is posted to my express.js web app. On certain routes a lot of middleware acts on that object, and it is also sent back to the user.

The issue is that some of the middleware, which operates on the user is asynchronous and modifies the user object. Also I try to send the user object back in the response as soon as possible.

Given that Javascript uses call-by-sharing, I am not sure what happens to the object as its properties are modified by async functions (perhaps before the object is sent back). Here is what I am talking about.

// This would be called after a post request
app.use(function (req, res, user) {
    asyncSaveCartInDataBase(user, function (user) {
       // Just an example
       user.cart.push('things')
    })
    user.cart = []
    res.json(user);
});

Here, asyncSaveCartInDataBase is called, which needs the full, unmodified cart property of the user. However, in an effort to send back the response from my server as soon as possible (and because user.cart will always be an empty array at the end) I set user.cart to an empty array and immediately send it back.

If JS made a copy of the object I wouldn't have to worry, but it does not, so I do not know what the value of user.cart is when it comes to the callback of asyncSaveCartInDataBase.

Is there a way to use the async nature of JS and node to change user.cart property and immediately send it back while not modifying the property for it's use in the asynchronous functions. Do I have to make a deep clone or something?

Upvotes: 1

Views: 76

Answers (1)

Andrew Eisenberg
Andrew Eisenberg

Reputation: 28757

What you are doing sounds like a bit of a nightmare. You have different middlewares operating on the same object. Some are mutating it, some are not, and some run out of order.

It seems to me that you have to separate your concerns a little more explicitly. It seems like there are two kinds of middlewares that you are using:

  1. Middleware that transforms the request into the response sent back to the user
  2. Middleware that requires the original request (or some variant of it)

My recommendation is this:

  1. Ensure that there is a single instance of the request that gets transformed by middlewares.
  2. Any middleware that requires its own, unmodified variant of the request must make a deep copy of all or part of the request that it requires.

JavaScript is asynchronous and single threaded, but that doesn't mean it is immune from race conditions. Shared state still causes problems and should be minimized as much as possible.

Upvotes: 4

Related Questions