简体   繁体   English

在 node.js 控制器中同步执行代码

[英]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. Promisesasyncawait语法旨在解决这个问题并使语法更加清晰。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM