How to simplify deep nested promises

I have come across a situation where I need to break at every "else" clause in a then(), and this doesn't look any better than nested callbacks, this is a login process:

User.findOne({
    username: username
}).exec()
    .then(user => {
        if (user) {
            return user.verifyPassAsync()
                .then(matched => {
                    if (matched) {
                        return User.getBriefProfile(username))
                            .then(emp => {
                                if (emp) {
                                    return saveToSession(emp);
                                } else {
                                    //return 
                                }})
                    } else {
                        //return ...
                    }})
        } else {
        // return false
        }
    })

Is there any way I can simplify this?

Answers:

Answer

Not really, as you're not (only) nesting promises here but rather conditionals. If written with async/await (ES7), your function would look like

var user = await User.findOne({username}).exec();
if (user) {
    var matched = await user.verifyPassAsync();
    if (matched) {
        var emp = await User.getBriefProfile(username);
        if (emp) {
            return saveToSession(emp);
        } else {
            // return …;
        }
    } else {
        // return …;
    }
} else {
    // return …;
}

As you can see, the nesting is inherent to your program. It's a bit simplified already though (no nesting for then calls), and you can do this right now with Promise.coroutine and ES6 generators.

Your best bet might be to throw an error in each else, and linearise the chain with that, .catching it in the end. Of course, if you are doing the same thing in each else block, then you could as well write

var user = await User.findOne({username}).exec();
if (user)
    var matched = await user.verifyPassAsync();
if (matched)
    var emp = await User.getBriefProfile(username);
if (emp) {
    return saveToSession(emp);
else
    // return …;

which easily translates back to then callbacks:

User.findOne({username: username}).exec()
.then(user =>
    user && user.verifyPassAsync()
).then(matched =>
    matched && User.getBriefProfile(username);
).then(emp =>
    emp ? saveToSession(emp) : …;
);

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.