[英]Execute code synchronously in node.js controller
幾周前剛開始使用 Node.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);
}
};
但是當我執行這個時,如果我顯示日志我有這個:
step1
step2
step4
step3
我知道它為什么這樣做,因為 JS 是異步多線程。 但我不知道如何執行這個塊(第 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);
}
);
當上一個區塊結束時。 這意味着,當hunterUser = createdUser;
被執行
編輯 :
感謝所有答案,我已經清理了我的代碼並退出了所有 then/catch 塊。 它減輕了很多重量:p並且可讀性很強。 這種方式的錯誤管理也容易得多
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);
}
};
顯然,您已經了解“異步”和“等待”是如何工作的。 現在只需記住將它們應用於每個網絡 I/O 操作。
所以如果你改變
await User.findOne({_id: req.body.id})
.then(currentUser => {
至
await User.findOne({_id: req.body.id})
.then(async currentUser => {
然后突然之間,您就可以在該塊內使用await
了。
現在你需要改變
User.findOne({email: formValue.hunterEmail})
.then(hunterUser => {
至
await User.findOne({email: formValue.hunterEmail})
.then(hunterUser => {
您當前的解決方案基本上是說“找到用戶,一旦你完成了這個和那個......”然后你實際上並沒有等到找到用戶,所以基本上必須修復。
更好的是,您可以刪除所有 '.then()' 和 '.catch' 塊,因為它們可以很容易地替換為“async/await”語法。
所以不要寫
await User.findOne({email: formValue.hunterEmail})
.then(hunterUser => { ...someLogic })
用更現代的方式你可以寫
const hunerUser = await User.findOne({email: formValue.hunterEmail});
//...someLogic
首先,您在同一行代碼中使用await
和.then()
,這不會產生任何值。 我建議單獨使用 ES6 async
await
關鍵字,這將使您的代碼部分在每個承諾解決后執行。
第 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);
}
任何應該在異步操作之后發生的邏輯都應該移到它的回調函數中。 目前你有這個結構:
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
});
如果您希望稍后執行代碼塊以響應userHelper.createUser
操作的完成,請將其移動到您響應該操作結果的回調:
User.findOne({email: formValue.hunterEmail})
.then(hunterUser => {
//...
userHelper.createUser(/*...*/)
.then((createdUser) => {
//...
// THIS IS THE CODE YOU WANT DO EXECUTE
});
});
總體而言,您似乎對大量復雜的嵌套回調感到困惑。 Promises
的async
和await
語法旨在解決這個問題並使語法更加清晰。 如果這些異步操作返回Promises
,那么絕對鼓勵您使用該語法而不是所有這些.then()
回調。
但即使使用.then()
語法,您需要做的只是識別代碼塊及其所屬位置。 某些東西應該立即執行(在.then()
之后),或者它應該響應異步操作(在.then()
內部)執行。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.