如何链接条件异步回调?

时间:2018-09-05 17:06:34

标签: javascript node.js express asynchronous

在node.js express项目中,我想为管理员用户实现切换到用户功能。管理员可以在框中输入用户名或用户ID。下面是处理此请求的代码。问题是,如果第一个数据库调用失败,则在继续登录代码之前,我需要用另一种查询重复该操作。如何在调用req.login之前添加条件异步调用?

router.route('/switchuser')
    .post(function (req, res) {
        mongoose.model('Users').findById(req.body.idOrName, function (err, user) {
            if (!user) {
                mongoose.model('Users').findOne({ username: req.body.idOrName }, function (err, user_) {
                    user = user_;
                    if (err) {
                        res.status(404);
                        res.send("User not found " + err);
                    }
                });
            }
            req.login(user, function (err) {
                if (err) {
                    res.status(404);
                    res.send("There was a problem switching the user: " + err);
                }
                else {
                    res.format({
                        html: function () {
                            res.redirect("/");
                        }
                    });
                }
            })
        });
    });

1 个答案:

答案 0 :(得分:0)

您正在经历回调地狱。当通过ID找不到用户时,您将启动第二个回调。问题是您的登录名因为方法在第二个回调之外执行,这意味着它不等待响应。回调地狱会迅速导致大量重复代码。一种解决方案是将您的通用代码提取到函数中。以下是如何执行此操作的一个示例。请注意,loginAs可能会在两个不同的位置被调用,这取决于是通过ID查找用户还是需要附加查找。

router.route('/switchuser')
    .post(function (req, res) {
        mongoose.model('Users').findById(req.body.idOrName, function (err, user) {
            if (err) {
                sendErrorResponse(err);
                return;
            }

            if (user) {
                loginAs(user, req, res);
                return
            }

            mongoose.model('Users').findOne({ username: req.body.idOrName }, function (err, user) {
                if (err) {
                    sendErrorResponse(err, req, res);
                    return;
                }

                if (!user) {
                    sendNotFoundResponse(req, res);
                    return;
                }

                loginAs(user, req, res);
            });
    });
});

function loginAs(user, req, res) {
    req.login(user, function (err) {
        if (err) {
            res.status(404);
            res.send("There was a problem switching the user: " + err);
        }
        else {
            res.format({
                html: function () {
                    res.redirect("/");
                }
            });
        }
    })
}

function sendErrorResponse(err, req, res) {
    res.status(500);
    res.send("Failed to switch user " + err);
}

function sendNotFoundResponse(req, res) {
    res.status(404);
    res.send("Could not find user");
}

现在,根据您使用的Mongoose JS版本,Promises的受限版本可能为available already。您的代码可以像这样进一步清理。

router.route('/switchuser')
    .post(function (req, res) {
        mongoose.model('Users').findById(req.body.idOrName)
            .then(function (user) {
                // If the user was found, return it down the chain
                if (user) {
                    return user;
                }

                // If the user was not found, return the promise for the next query
                return mongoose.model('Users').findOne({ username: req.body.idOrName });
            })
            .then(function(user) {
                if (!user) {
                    sendNotFoundResponse(req, res);
                    return;
                }

                loginAs(user, req, res);
            })
            .catch(function(err) {
                sendErrorResponse(err, req, res);
            });
    });
});

function loginAs(user, req, res) {
    req.login(user, function (err) {
        if (err) {
            res.status(404);
            res.send("There was a problem switching the user: " + err);
        }
        else {
            res.format({
                html: function () {
                    res.redirect("/");
                }
            });
        }
    })
}

function sendErrorResponse(err, req, res) {
    res.status(500);
    res.send("Failed to switch user " + err);
}

function sendNotFoundResponse(req, res) {
    res.status(404);
    res.send("Could not find user");
}

您会看到诺言,您可以将所有错误集中在一个catch的底部。更少的重复代码和方法调用可以使结果更干净。您可能需要执行exec才能访问catch方法。只需阅读Mongoose文档,就可以了。