We've got this node.js code which is called by an Express route:

routes.login = (req, res) => {

let inpEmail = req.body.email.toLowerCase(),

// find the user
User.findOne({
email: inpEmail
}).exec()
.then((user) => {

if (user.isLocked && Date.now < user.lockExpiry) {
//some logic here
} else if (!user.emailVerified) {
//some logic here
} else {

if (compareResult) {

//some logic here

.then(() => {
//some logic here
})
.catch((err) => {
//some logic here
});
})
.catch((err) => {
//some logic here
});

} else {

.then(() => {
//some logic here
})
.catch((err) => {
//some logic here
});
}
});
}
})
.catch((err) => {
//some logic here
});
}


All looks good, and we feel that the promises are not used correctly; there are multiple catch statements.

One of my colleague said that:

Ideally, the code structure with promises shall look like this:

someFunction()
.then()
.then()
.then()
.catch();


Since, there are multiple if-else statements. We were trying to brainstorm if the above kind of chaining can be implemented or not.

Is there a better way to implement promises in this code?

This is missing the point. It is not about promises. You are right that if done correctly, you'll get a nice flat structure, but not if you inline all your code. This would be true if you weren't using promises as well. What you should do is split your code into smaller building blocks, and the nice structure will follow.

Also, be wary of your variable names:

// check if password matches
if (compareResult) {


Why not rename "compareResult" "passwordIsCorrect" and get rid of the comment?

// find the user
User.findOne({


That comment is useless.

Basically all the comments can be removed. Try to explain yourself with code instead, and only comment what can't be explained with code.

Just a quick example of the type of refactoring I would do:

routes.login = (req, res) => {
let inpEmail = req.body.email.toLowerCase();

User.findOne({email: inpEmail})
.exec()
.then((user) => {
if(user.isLocked && Date.now < user.lockExpiry){
return blabla();
}else if(!user.emailVerified){
return requireEmailVerification();
}else{
}
})
.then(() => {
// Probably res.send() here
})
.catch((err) => {
//some logic here
});
};

}

});
}

.then(() => {
//some logic here
})
.catch((err) => {
//some logic here
});
}