Passing a callback to a function that is prefixed with await. Order of excecution

68
January 24, 2018, at 7:44 PM

Let's say we have a mongoDB with cars, and users can add cars. The goal is to prevent more than one car with an identical license plate to be saved. Stack is node/express and mongoose.

Scenario: A car with the provided license plate DOES already exist in the db.

First attempt:

console.log('Before check')
await Car.findOne({ licensePlate }, (err, foundCar) => {
  if (err) return next(err)
  if (foundCar) return res.status(400).send('license plate exists already in db.')
})
console.log('After check')
// some other code, saving to db and stuff
return res.status(200).send('The car was saved succesfully.')

My naive expectation was that if i prefix moongooses findOne function with an await keyword, the code after the "await block" will not be executed because a car is found and then the request is terminated by sending a 400 response. What happens instead is that the code after the "await block" is executed which results in a

Error: Can't set headers after they are sent.

Second attempt:

console.log('Before check')
try {
  const foundCar = await Car.findOne({ licensePlate })
  if (foundCar) return res.status(400).send('license plate exists already in db.')
} catch (err) {
  return next(err)
}
console.log('After check')
// some other code, saving to db and stuff
return res.status(200).send('The car was saved succesfully.')

This works as expected and prevents any code from exceduting after the if(foundCar) check

Question: Can someone enlighten me what happens here in attempt one? Looking at it now it does feel weird to combine a callback with an await keyword, but apperently i don't understand async/await enough to really see what's happening here. Does await in this case mean that "the code waits" only for findOne to finish and then the callback and the rest of the code run at the same time? Any pointer to useful ressources to fully understand what's going on would be very much appreciated.

Answer 1
  1. If the findOne function is not passed a callback function, it returns a Promise object.
  2. If await is invoked with a Promise object, it will wait till the value is resolved by the promise and return the value.
  3. If await is invoked with a non Promise object, it will convert that to a resolved promise.

In the first case, a callback is passed to the findOne, so it is not returning a Promise object and await converts that to a resolved promise. The value of that is resolved in the nextTick of the Node.js execution cycle. So there is no waiting for the results is happening here and even before the callback function is invoked response 200 is sent. When the callback is actually executed, it is trying to send the response headers again and since they are already sent, you are getting this error.

In the second case, findOne actually returns a Promise object. So await waits till the Promise resolves to a value. That is why the second case is working properly.

READ ALSO
can i send a parameter in request to auth API endpoint using passport.js

can i send a parameter in request to auth API endpoint using passport.js

I'm using a facebook login with passportjs, and saving the user data in my mongodb if the user doesn't existhere is the model of mongodb i'm saving users data in

85
Scrape the times when users like my Facebook page posts

Scrape the times when users like my Facebook page posts

I found this Facebook scraper on GitHub which scrapes for every post like a Like_ID ( The ID of a like ), person_hash_id ( The hashed ID of the liker ), and post_id( The ID of the liked post )

76
Python: find x along cubic spline (returning y) which yields sequential (x,y) pairs in equal distance

Python: find x along cubic spline (returning y) which yields sequential (x,y) pairs in equal distance

assume I have a cubic spline from point [0,0] to [10,10], with boundary values of zero derivative:

123
Avoiding np.where when assigning to numpy array

Avoiding np.where when assigning to numpy array

I would like for the following (or similar) to work (without using npwhere)

172