Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chaining ES6 promises without nesting

I'm trying to chain a second then method after the first one but it's not working correctly for some reason. It only works fine when I'm nesting the then method. Here's the code that doesn't work correctly:

auth.post('/signup', (req, res, next) => {

  const { username } = req.body
  const { password } = req.body

  Users.findOne({ username })
    .then(
      existingUser => {
        if (existingUser) return res.status(422).send({ error: 'Username is in use' })

        const user = new Users({ username, password })
        user.save()
      },
      err => next(err)
    )
    .then(
      savedUser => res.send({ 
        username: savedUser.username, 
        password: savedUser.password 
      }),
      err => next(err)
    )
})

Here when I post to '/signup' user gets saved into the database but I don't get the response with username and password. However:

auth.post('/signup', (req, res, next) => {

  const { username } = req.body
  const { password } = req.body

  Users.findOne({ username })
    .then(
      existingUser => {
        if (existingUser) return res.status(422).send({ error: 'Username is in use' })

        const user = new Users({ username, password })
        user.save()
        .then(
          savedUser => res.json({ 
            username: savedUser.username,
            password: savedUser.password
          }),
          err => next(err)
        )
      },
      err => next(err)
    )
})

This works as expected. user gets saved and I get the response with username and password. I've read that you can chain these then methods in a flat way without nesting. But I've checked questions on here and couldn't find an answer as to what I'm doing wrong here. Can someone please help with this issue?

like image 421
avatarhzh Avatar asked Feb 26 '26 08:02

avatarhzh


1 Answers

Simple 3 step process:

  1. Return a promise from the first .then call.

Change this:

// ...
const user = new Users({ username, password })
user.save()
// ...

to this:

// ...
const user = new Users({ username, password })
return user.save()
// ...

(Mind the return keyword, which will chain it with the second .then() call)


2. Reject the Promise in case existingUser returns false (thanks @JaromandaX for pointing out)

Change this:

if (existingUser) return res.status(422).send({ error: 'Username is in use' })

to this:

if (existingUser) {
    res.status(422).send({ error: 'Username is in use' });
    return Promise.reject('USER_EXISTS');
}

3. Drop the .then(onResolvedFunction, onRejectedFunction) pattern when possible, and use .catch(err) instead (to catch for a bigger spectrum of errors).

Delete the second argument from your .then()'s

,
err => next(err)

use a .catch instead:

Users.findOne({ username })
    .then(...)
    .then(...)
    .catch((e) => { // <-- Handle the error properly
         console.log(e);
         if (e !== 'USER_EXISTS')
             next(err);
     }); 

Mongoose Footnote!

This has nothing to do with promises. I see you named your model Users, but remember that, internally, Mongoose will pluralize your model names for you. You should either:

  • Name your model User; or

  • Explicitly set the pluralized form in a third argument, like this:

    const Users = mongoose.model('User', UserSchema, 'Users');

like image 140
Jose Lopez Garcia Avatar answered Feb 27 '26 22:02

Jose Lopez Garcia



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!