Just started with Node.js few weeks ago, i'm trying to execute this code synchronously located in my controller
Quest.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. But i can't figure out how to execute this block (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);
}
);
When the previous block is over. That mean, when hunterUser = createdUser; is executed
EDIT :
Thanks to all answers, i have cleaned my code and went out of all the then/catch block. It lost a lot of weight :p and so much readable. 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);
}
};
hunterUser = createdUser;is executed" - That's what the callback function you're using is for. See the blank line right after that line of code? Whatever you want to happen after that line of code would go right there, within that overall.then()function.