mcAngular2
mcAngular2

Reputation: 309

How to handle kind of nested Promises in NodeJS

I'm, relatively new to Promises, so I hope you can help me. I have the following code:

bcrypt.genSalt(10)
    .then((salt) =>{
        return  bcrypt.hash(newUser.password, salt)
    })
    .then((hash)=>{
        newUser.password = hash;
        return mariaDB.pool.getConnection()
    })
    .then((conn)=>{
        conn.beginTransaction()
            .then() //here I'm doing some database request
            .catch((err)=>{
                console.log(err)
                return conn.rollback() //where is this Promise handled?
            })
    })
    .catch((err)=>{
        res.json({error: err})
    })

I receive a newUser object, which I first pass to bcrypt to encrypt my password. Then I need to make a transaction to my MariaDB database. But is this kind of "nested Promises" correct? Is there a better solution? Where is the promise "return conn.rollback" handled?

Greetings and Thanks!

Upvotes: 0

Views: 210

Answers (4)

аlex
аlex

Reputation: 5698

Do it simple like this:

bcrypt.genSalt(10)
    .then(salt => bcrypt.hash(newUser.password, salt))
    .then(hash => {
        newUser.password = hash;
        return mariaDB.pool.getConnection()
    })
    .then(conn => {
       return conn.beginTransaction()
          .then(() => {
              // here I'm doing some database request
          })
          .catch( err => {
            conn.rollback();
            throw new Error(err); // this error will be cathed on bottom catch
          });
    })
    .catch(err => res.json({error: err}))

Upvotes: 2

Abrar
Abrar

Reputation: 7232

A rewrite with async/await (making your life easier by getting rid of all those nested promises, thank me later!) would look like this:

try {
  const salt = await bcrypt.genSalt(10);
  const hash = await bcrypt.hash(newUser.password, salt);
  newUser.password = hash;
  const conn = await mariaDB.pool.getConnection();
  try {
    const transaction = await conn.beginTransaction();
    // your db calls
  } catch (err) {
    console.log(err);
    return conn.rollback();
  }
} catch (err) {
  res.json({error: err})
}

Please make sure you wrap this block within an async function. For example, for self-invoking function use:

(async() => {
 // the block of code using await ...
})();

Upvotes: 0

Estus Flask
Estus Flask

Reputation: 223114

return conn.rollback() //where is this Promise handled?

is not handled, this is the problem with this snippet. Nested promises should be chained in order to maintain proper control flow, i.e. returned from then and catch callbacks:

.then((conn)=>{
    return conn.beginTransaction()
    ...

Nested promise is required because conn should be available in then callbacks. A more convenient way to handle this is async..await, this allows to flatten nested promises:

try {
    const salt = await bcrypt.genSalt(10)
    const hash = await bcrypt.hash(newUser.password, salt)
    newUser.password = hash;
    const conn = await mariaDB.pool.getConnection()
    try {
        conn.beginTransaction()
        // ...
    } catch (err) {
        await conn.rollback()
    }
} catch (err) {
    res.json({error: err})
}

A good thing would be to rethrow an error after rollback because it's clear that things went wrong at this point.

Upvotes: 0

siddhant sankhe
siddhant sankhe

Reputation: 633

bcrypt.genSalt(10)
.then((salt) =>{
    return  bcrypt.hash(newUser.password, salt)
})
.then((hash)=>{
    newUser.password = hash;
    return mariaDB.pool.getConnection()
})
.then((conn)=>{
    return dbops(conn)
})
.catch((err)=>{
    res.json({error: err})
})

// added new function db ops

function dbops(conn){
   return new Promise(function(resolve,reject){
       conn.beginTransaction()
          .then((data)=>{
            //db stuff
            resolve("db stuff done")
        }).catch((err)=>{
            console.log(err)
            conn.rollback()
            reject(err)
        })
     })}

Hope this will help you.

Upvotes: 1

Related Questions