[英]Execute code synchronously in node.js controller
Just started with Node.js few weeks ago, i'm trying to execute this code synchronously located in my controller几周前刚开始使用 Node.js,我正在尝试在我的控制器中同步执行此代码
Quest.js
任务.js
async function create(req, res, next) {
const formValue = req.body['form'];
let quest;
const riddles = [];
try {
//get current user who created this Quest
await User.findOne({_id: req.body.id})
.then(currentUser => {
/*-------------------------------START QUEST CREATION-------------------------------*/
quest = new Quest({
admin: currentUser,
hunter: new User,
launchDate: formValue.launchDate,
penaltyTime: formValue.penaltyTime,
});
/*-------------------------------END QUEST CREATION-------------------------------*/
/*-------------------------------START RIDDLES CREATION-------------------------------*/
let riddle;
console.log('step1');
//Riddles instantiation
for (const [key, participantEmail] of Object.entries(formValue.participantsEmail)) {
if (formValue.riddle.text == "") {
throw ('errorMsg:IncorrectRiddleText/code:422/field:riddleText');
}
if (formValue.riddle.answer == "") {
throw ('errorMsg:IncorrectRiddleAnswer/code:422/field:riddleAnswer');
}
//if its the first riddle => i.e : the one created by the current user
if (`${key}` == 0) {
riddle = new Riddle({
quest: quest,
author: currentUser,
authorEmail: currentUser.email,
text: formValue.riddle.text,
answer: formValue.riddle.answer,
status: true,
nextRiddle: null
});
}
//if it's a waiting riddle
else {
if (!validator.validateEmail(participantEmail.participantEmail)) {
throw ('errorMsg:IncorrectEmail/code:422/field:participantEmail');
}
if (participantEmail.participantEmail)
riddle = new Riddle({
quest: quest,
authorEmail: `${participantEmail.participantEmail}`,
nextRiddle: null
});
//assign last created riddle to the one before to make the good order
riddles[`${key}` - 1].nextRiddle = riddle;
}
//create riddle list for Quest
riddles.push(riddle);
}
/*-------------------------------END RIDDLES CREATION-------------------------------*/
/*-------------------------------START USER MANAGEMENT-------------------------------*/
//create a User for the hunter or if he already have an account => link it to the new Quest
User.findOne({email: formValue.hunterEmail})
.then(hunterUser => {
console.log('step2');
if (hunterUser == null) {//if userHunter doesn't exist yet => create it
userHelper.createUser(
formValue.hunterFirstName,
formValue.hunterLastName,
formValue.hunterFirstName + formValue.hunterLastName.slice(-1),
formValue.hunterEmail,
Text.generateRandomPassword()
).then((createdUser) => {
console.log('step3');
hunterUser = createdUser;
}).catch(error => {
console.log('error1')
error = Text.parseErrorToObject(error)
return res.status(parseInt(error.code.toString())).json(error);
}
);
}
console.log('step4');
questHelper.saveQuest(quest, riddles, hunterUser)
.then(() => {
console.log('step5');
return res.status(200).json({'msg': 'Quest created'})
})
.catch(error => {
console.log('error2')
error = Text.parseErrorToObject(error)
return res.status(parseInt(error.code.toString())).json(error);
}
);
}
).then().catch(error => {
throw (Text.parseErrorToObject(error));
})
/*-------------------------------END USER MANAGEMENT-------------------------------*/
})
.catch(error => {
throw (Text.parseErrorToObject(error));
}
);
} catch (e) {
console.log('error3')
return res.status(parseInt(e.code.toString())).json(e);
}
};
But when i execute this if i display the logs ihave this :但是当我执行这个时,如果我显示日志我有这个:
step1
step2
step4
step3
I know why it's doing this, du to the fact that JS is asynchronous multi-thtreading.我知道它为什么这样做,因为 JS 是异步多线程。 But i can't figure out how to execute this block (step4) :
但我不知道如何执行这个块(第 4 步):
questHelper.saveQuest(quest, riddles, hunterUser)
.then(() => {
console.log('step5');
return res.status(200).json({'msg': 'Quest created'})
})
.catch(error => {
console.log('error2')
error = Text.parseErrorToObject(error)
return res.status(parseInt(error.code.toString())).json(error);
}
);
When the previous block is over.当上一个区块结束时。 That mean, when
hunterUser = createdUser;
这意味着,当
hunterUser = createdUser;
is executed被执行
EDIT :编辑 :
Thanks to all answers, i have cleaned my code and went out of all the then/catch block.感谢所有答案,我已经清理了我的代码并退出了所有 then/catch 块。 It lost a lot of weight :p and so much readable.
它减轻了很多重量:p并且可读性很强。 The error management is so much easier this way too
这种方式的错误管理也容易得多
async function create(req, res, next) {
const formValue = req.body['form'];
const riddles = [];
try {
//get current user who created this Quest
const currentUser = await User.findOne({_id: req.body.id});
/*-------------------------------START QUEST CREATION-------------------------------*/
let quest = await new Quest({
admin: currentUser,
hunter: new User,
launchDate: formValue.launchDate,
penaltyTime: formValue.penaltyTime,
});
/*-------------------------------END QUEST CREATION-------------------------------*/
/*-------------------------------START RIDDLES CREATION-------------------------------*/
let riddle;
//Riddles instantiation
for (const [key, participantEmail] of Object.entries(formValue.participantsEmail)) {
if (formValue.riddle.text == "") {
throw ('errorMsg:IncorrectRiddleText/code:422/field:riddleText');
}
if (formValue.riddle.answer == "") {
throw ('errorMsg:IncorrectRiddleAnswer/code:422/field:riddleAnswer');
}
//if its the first riddle => i.e : the one created by the current user
if (`${key}` == 0) {
riddle = new Riddle({
quest: quest,
author: currentUser,
authorEmail: currentUser.email,
text: formValue.riddle.text,
answer: formValue.riddle.answer,
status: true,
nextRiddle: null
});
}
//if it's a waiting riddle
else {
if (!validator.validateEmail(participantEmail.participantEmail)) {
throw ('errorMsg:IncorrectEmail/code:422/field:participantEmail');
}
if (participantEmail.participantEmail)
riddle = new Riddle({
quest: quest,
authorEmail: `${participantEmail.participantEmail}`,
nextRiddle: null
});
//assign last created riddle to the one before to make the good order
riddles[`${key}` - 1].nextRiddle = riddle;
}
//create riddle list for Quest
riddles.push(riddle);
}
/*-------------------------------END RIDDLES CREATION-------------------------------*/
/*-------------------------------START USER MANAGEMENT-------------------------------*/
//create a User for the hunter or if he already have an account => link it to the new Quest
let hunterUser = await User.findOne({email: formValue.hunterEmail});
if (hunterUser == null) {//if userHunter doesn't exist yet => create it
hunterUser = await userHelper.createUser(
formValue.hunterFirstName,
formValue.hunterLastName,
formValue.hunterFirstName + formValue.hunterLastName.slice(-1),//TODO add a unique ID
formValue.hunterEmail,
Text.generateRandomPassword()
)
}
await questHelper.saveQuest(quest, riddles, hunterUser)
return res.status(200).json({'msg': 'Quest created'})
/*-------------------------------END USER MANAGEMENT-------------------------------*/
} catch (error) {
error = Text.parseErrorToObject(error);
return res.status(parseInt(error.code.toString())).json(error);
}
};
clearly you already understand how "async" and "await" work.显然,您已经了解“异步”和“等待”是如何工作的。 Now it's just about remembering to apply them for every network I/O operation.
现在只需记住将它们应用于每个网络 I/O 操作。
And so if you change所以如果你改变
await User.findOne({_id: req.body.id})
.then(currentUser => {
to至
await User.findOne({_id: req.body.id})
.then(async currentUser => {
then suddenly you'll be able to use await
inside that block.然后突然之间,您就可以在该块内使用
await
了。
Now you need to change现在你需要改变
User.findOne({email: formValue.hunterEmail})
.then(hunterUser => {
to至
await User.findOne({email: formValue.hunterEmail})
.then(hunterUser => {
your current solution basically says "find user and once you're done do this and that..." and then you don't actually wait until the user is found, so that basically has to be fixed.您当前的解决方案基本上是说“找到用户,一旦你完成了这个和那个......”然后你实际上并没有等到找到用户,所以基本上必须修复。
Better yet, you could drop all of the '.then()' and '.catch' blocks since they can be easily replaced with the "async/await" syntax.更好的是,您可以删除所有 '.then()' 和 '.catch' 块,因为它们可以很容易地替换为“async/await”语法。
So instead of writing所以不要写
await User.findOne({email: formValue.hunterEmail})
.then(hunterUser => { ...someLogic })
in a more modern way you could write用更现代的方式你可以写
const hunerUser = await User.findOne({email: formValue.hunterEmail});
//...someLogic
First, you're using await
and .then()
at the same line of code, which won't produce any value.首先,您在同一行代码中使用
await
和.then()
,这不会产生任何值。 I'd suggest using the ES6 async
await
keywords alone which will make your parts of code execeute after each promise has resolved.我建议单独使用 ES6
async
await
关键字,这将使您的代码部分在每个承诺解决后执行。
Step 4 should look something like this:第 4 步应如下所示:
try {
const result = await questHelper.saveQuest(quest, riddles, hunterUser);
console.log('step5');
return res.status(200).json({'msg': 'Quest created'})
}
catch (error) {
console.log('error2')
error = Text.parseErrorToObject(error)
return res.status(parseInt(error.code.toString())).json(error);
}
Any logic that should happen after the asynchronous operation should be moved to its callback function.任何应该在异步操作之后发生的逻辑都应该移到它的回调函数中。 Currently you have this structure:
目前你有这个结构:
User.findOne({email: formValue.hunterEmail})
.then(hunterUser => {
//...
userHelper.createUser(/*...*/)
.then((createdUser) => {
//...
// YOU WANT TO DO SOMETHING HERE
});
// THIS IS THE CODE YOU WANT DO EXECUTE ABOVE
});
If you want that later block of code to be executed in response to the completion of the userHelper.createUser
operation, move it to the callback where you respond to the result of that operation:如果您希望稍后执行代码块以响应
userHelper.createUser
操作的完成,请将其移动到您响应该操作结果的回调:
User.findOne({email: formValue.hunterEmail})
.then(hunterUser => {
//...
userHelper.createUser(/*...*/)
.then((createdUser) => {
//...
// THIS IS THE CODE YOU WANT DO EXECUTE
});
});
Overall it seems you're getting confused by a large and complex set of nested callbacks.总体而言,您似乎对大量复杂的嵌套回调感到困惑。 The
async
and await
syntax for Promises
is meant to address that and make the syntax more clear. Promises
的async
和await
语法旨在解决这个问题并使语法更加清晰。 If these asynchronous operations return Promises
then you're definitely encouraged to make use of that syntax instead of all of these .then()
callbacks.如果这些异步操作返回
Promises
,那么绝对鼓励您使用该语法而不是所有这些.then()
回调。
But even with the .then()
syntax, all you need to do is identify your blocks of code and where they belong.但即使使用
.then()
语法,您需要做的只是识别代码块及其所属位置。 Either something should execute immediately (after the .then()
), or it should execute in response to an asynchronous operation (inside the .then()
.某些东西应该立即执行(在
.then()
之后),或者它应该响应异步操作(在.then()
内部)执行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.