Node.js 在一种情况下使用异步代码的if/else
我在异步代码方面没有太多经验,我遇到了一个问题,以下是我的代码:Node.js 在一种情况下使用异步代码的if/else,node.js,express,asynchronous,Node.js,Express,Asynchronous,我在异步代码方面没有太多经验,我遇到了一个问题,以下是我的代码: if (!req.params.user_name) { req.params.user = req.me; } else { User.findOne({username: req.params.user_name}, '_id', (error, user) => { if (error) { return next(error); }
if (!req.params.user_name) {
req.params.user = req.me;
} else {
User.findOne({username: req.params.user_name}, '_id', (error, user) => {
if (error) {
return next(error);
}
if (!user) {
let error = new Error('User not found');
return next(error);
}
req.params.user = user;
});
}
Account.findOne({name: req.params.account_name, created_by: req.params.user})
.populate(['currency', 'created_by'])
.exec((err, account) => {
if (err) {
return next(err);
}
return res.send(account);
});
正如您所看到的,问题是,在一种情况下,我只需要执行一个简单的过程操作,在另一种情况下,我必须查询异步数据库,然后执行下面的代码。我不能简单地将帐户查询放在用户查询的回调中,因为我不需要一直执行用户查询。
我试图在这里找到答案,但我找到的唯一结果是关于执行一个或另一个异步任务(例如:)。
根据本文的建议,我考虑将代码包装在匿名函数中的if块中,并执行以下操作:
let get_user;
if (!req.params.user_name) {
let get_user = () => {req.params.user = req.me};
} else {
let get_user = User.findOne({username: req.params.user_name}, '_id', (error, user) => {
if (error) {
return next(error);
}
if (!user) {
let error = new Error('User not found');
return next(error);
}
req.params.user = user;
});
}
get_user().then(() => {
Account.findOne({name: req.params.account_name, created_by: req.params.user})
.populate(['currency', 'created_by'])
.exec((err, account) => {
if (err) {
return next(err);
}
return res.send(account);
});
});
但我觉得这很奇怪,我想我需要从if块中的匿名函数返回一个承诺
那么,解决这个问题的优雅方法是什么呢?我在空闲时间学习node.js,如有任何一般性建议,将不胜感激
谢谢您的时间。回调不应与猫鼬一起使用;它长期以来一直支持承诺 这个 无法工作,因为
get\u用户
需要返回承诺
通常是这样做的:
let userPromise;
if (!req.params.user_name) {
userPromise = Promise.resolve(req.me);
} else {
userPromise = User.findOne(...);
}
userPromise().then((user => {
req.params.user = user;
return Account.findOne(...);
});
请注意,req.params.user
是这两种情况的通用代码。这可以通过async..wait
方便地完成,它是承诺的语法糖:
try {
let user;
if (!req.params.user_name) {
user = req.me;
} else {
user = await User.findOne({username: req.params.user_name}, '_id');
}
req.params.user = user;
const account = await Account.findOne({name: req.params.account_name, created_by: req.params.user})
.populate(['currency', 'created_by'])
.exec();
res.send(account);
} catch (err) {
next(err);
}
这应该是一个async
中间件函数的主体,在原始代码中没有显示
正如中所解释的,Express本身不支持承诺,所有的
async
中间件和路由处理程序都应该用try..catch
包装以进行错误处理。好的,昨天我做了一些类似的事情来实现它:if(!req.params.user_name){get_user=()=>{return new Promise((resolve)=>{对于else块也是这样,然后执行“get_user()。然后(()=>{”通过阅读您的代码,我发现我不需要在if块中实例化承诺,只需静态调用它,也不需要将其封装在匿名函数中,在else块中我将解析User.findOne的结果。您确认了吗?将同步代码放入其中对我来说有点不安一个承诺,但它现在更有意义。至于async..Wait示例,这是否意味着如果我不进行回调,User.findOne将自动返回结果,如果有回调,将自动抛出错误?这将非常好,而且更直观,因为它看起来像同步代码。感谢您的解释,它确实清除了是的,你根本不需要匿名函数。你需要承诺。如果你使用原始承诺,解决,因为你需要与链接的东西,那么,这就是为什么在第一个代码段中有userPromise
。User.findOne返回结果的承诺。wait
是语法糖对于.then(result=>/*handle result*/,err=>/*抛出错误*)
。两个代码段在功能上是等效的,第二个代码段看起来更简单。由于您使用的是支持async/await的Node,我建议使用async/await。好的,我将尝试使用async。await,这将允许我清除所有地方的大量嵌套回调。谢谢您的时间。
try {
let user;
if (!req.params.user_name) {
user = req.me;
} else {
user = await User.findOne({username: req.params.user_name}, '_id');
}
req.params.user = user;
const account = await Account.findOne({name: req.params.account_name, created_by: req.params.user})
.populate(['currency', 'created_by'])
.exec();
res.send(account);
} catch (err) {
next(err);
}