ES6 promises chaining without nesting

I am trying to link the second method after the first, but it doesn't work correctly for some reason. It only works well when I nest 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 the message '/signup'

user

, it is saved in the database, but I am not getting a 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

is saved and I get a response with username and password. I read that you can bind these methods flat without nesting. But I checked the questions here and couldn't find an answer as to what I am doing wrong here. Can anyone help with this problem?

+3


source to share


2 answers


You have at least three problems with your chained version

  • You don't return anything from your first .then

  • in case of an existing user, the chain .then

    will run
  • in case of deviation in, the Users.findOne

    chain will also be executed.then

To fix it:



  • just return .save()

  • return a Promise.reject

    - alternatively you can throw

    run the error
  • don't use functions onRejected

    in .then

    , you just have one rejection handler at the end of the chain in.catch

I would link this code like this:

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

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

    Users.findOne({ username })
    .then(existingUser => {
        if (existingUser) {
            return Promise.reject({
                status:422,
                error: 'Username is in use' 
            });
        }
        return new Users({ username, password }).save();
    })
    .then(savedUser => res.send({ 
        username: savedUser.username, 
        password: savedUser.password 
    }))
    .catch(err => {
        if (err.status) {
            return res.status(err.status).send({ error: err.error });
        }
        return next(err);
    });
});

      

+1


source


A simple 3 step process:

  • Return a promise from the first call.then

    .

Change this:

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

      

:



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

      

(note the return keyword, which will link it to the second call .then()

)


2. Reject the promise in case it existingUser

returns false

(thanks @JaromandaX for pointing out)

Change this:

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

      

:



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

      


3. If possible, clear the pattern.then(onResolvedFunction, onRejectedFunction)

and use .catch (err) instead (to catch a wider range of errors).

Remove the second argument from <.then()

,
err => next(err)

      

use instead of .catch:

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

      


Mongoose Brief!

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 must either:

  • Name your model User

    ; or
  • Explicitly set the plural form in the third argument, for example:

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

+2


source







All Articles