Javascript 如何链接条件异步回调?

Javascript 如何链接条件异步回调?,javascript,node.js,express,asynchronous,Javascript,Node.js,Express,Asynchronous,在node.js express项目中,我想为管理员用户实现切换到用户功能。管理员可以在框中键入用户名或用户id。下面是处理此请求的代码。问题是,如果第一次数据库调用失败,我需要用另一种查询重复它,然后再继续使用登录代码。如何在调用req.login之前添加条件异步调用 router.route('/switchuser') .post(function (req, res) { mongoose.model('Users').findById(req.body.idOr

在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("/");
                        }
                    });
                }
            })
        });
    });

你正在经历地狱。当ID找不到用户时,启动第二个回调。问题是您的login-as方法在第二个回调之外执行,这意味着它不等待响应。回调地狱会很快导致大量重复代码。一种解决方案是将常见的代码位提取到函数中。下面是一个示例,说明了您可以如何做到这一点。请注意,
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的有限版本可能是。您的代码可以像这样进一步清理

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文档就可以了。

if语句在
req.login
之后没有出现。你的意思是说,
req.login
没有等待
mongoose.model('Users').findOne(…)
?使用回调模式,“等待”某件事情的唯一方法是在回调完成时调用回调内部的代码。是的,没错。我就是这个意思!有人关闭了此项(不确定为什么关闭此项。您正在经历回调地狱。这可以通过回调解决(正确完成时)但是你可能会考虑承诺或者异步等待,它会清理代码。bit@deceze如果你要在评论中回答,为什么要关闭这个问题?谢谢你的帮助!它工作得很好,但我必须删除第一个if子句“if(err)”,否则它就不工作了。