繁体   English   中英

在异步函数中使用While循环?

[英]Using While loop inside async function?

我试图在异步函数中使用while循环,并且怀疑我的resolve(); 正在弄乱循环,但是我不确定该怎么做。 这是我的代码:

app.get("/meal-plan", async function(req, res) {
    var calorieCount = req.query.calorieCount;
    var mealInput = parseInt(req.query.mealInput);
    var dietInput = req.query.food;
    var goalPerMeal = (calorieCount / mealInput);
    var whichDiet = "diet." + dietInput;

    var breakfastGoal = goalPerMeal;

    var breakfastArr = [];

    async function getBreakfastArr() {
        return new Promise((resolve, reject) => {
            var breakfastQuery = {"breakfast": true, [whichDiet]: true};

            while (breakfastGoal >= 150) {
                Food.count(breakfastQuery, function(err, count) {
                    if (err) {
                        console.log(err);
                    } else {
                        var random = Math.floor(Math.random() * count);

                        Food.findOne(breakfastQuery).skip(random).exec(
                            function(err, result) {
                                if (err) {
                                    console.log(err);
                                } else {
                                    breakfastGoal -= result.nutrition.calories;
                                    breakfastArr.push(result);
                                    resolve();
                                }
                             });
                    }
                })
            }
        });
    }

    try {
        await getBreakfastArr();
        console.log(breakfastArr);

        res.render("meal-plan.ejs", { meal: mealInput, calories: calorieCount, diet: dietInput, breakfast: breakfast, lunch: lunch, dinner: dinner, totalCalories: totalCalories});

    } catch (e) {
        res.json(e);
    }
});    

goalPerMeal变量接受用户的卡路里输入,并将其除以他们在我的表格上选择的进餐次数。 然后,我将该值设置为一个名为breakfastGoal的特定早餐变量。 异步函数从我的数据库中找到一个随机配方,并将其添加到我的数组breakfastArr 找到食谱后,就会从breakfastGoal减去该食谱的卡路里计数。

我希望运行此功能,直到breakfastGoa l降低到150以下; 但是,它似乎不起作用。 如果删除while循环,该函数将成功找到早餐项目,将其添加到数组中,并从breakfastGoal减去其卡路里计数。 打破它的唯一一件事就是添加while循环。

这与resolve();resolve(); 在异步功能中,还是我缺少重要的东西?

任何帮助都非常感谢。

您认为这样的事情会起作用吗? 我还没有测试。 只是一个主意。 将while块放入else块中,然后递归调用。

async function getBreakfastArr() {
  let breakfastQuery = { "breakfast": true, [whichDiet]: true };
  return this.getRandomRecipe(breakfastQuery).then((response)=>{
        return response; //the response will have your breakfast goal
  });
}


async function getRandomRecipe(breakfastQuery) {

   return Food.count(breakfastQuery, function (err, count) {
    if (err) {
      console.log(err);
    } else {
      var random = Math.floor(Math.random() * count);
      Food.findOne(breakfastQuery).skip(random).exec(
        function (err, result) {
          if (err) {
            console.log(err);
          } else {
            breakfastGoal -= result.nutrition.calories;
            breakfastArr.push(result);
            while (breakfastGoal >= 150) {
               this.getRandomRecipe(breakfastQuery);
            }
            return Promise.resolve(breakfastGoal);
          }
        });
    }
  })
}

问题在于,您仅创建一个Promise,但是需要在while循环中等待多个异步结果。

第一次调用resolve ,将解决唯一的诺言,这将使代码在await执行之后。 但是那时您的阵列还没有完成。 同样,任何进一步resolve呼吁将不再影响承诺:承诺只能被解决一次。 其他呼叫将被忽略。

解决方案是在while循环的每次迭代中做出承诺,然后await

更改此:

    return new Promise((resolve, reject) => {
        var breakfastQuery = {"breakfast": true, [whichDiet]: true};
        while (breakfastGoal >= 150) {

对此:

    var breakfastQuery = {"breakfast": true, [whichDiet]: true};
    while (breakfastGoal >= 150) {
        await new Promise((resolve, reject) => {

该代码可以进一步改进,但是与您的问题无关。 例如,最好使用要添加到数组breakfastArr的值来使每个promise解析,这样您将具有:

        breakfastArr.push(await new Promise((resolve, reject) => {
             // ...
                           resolve(result)
             // ...
        });

并且async函数应该返回该数组,因此不必在顶部定义它。

这里的问题是,您正在混合使用回调函数和promise。 正确的方法是将仅采用回调的函数包装在promise构造函数中。 结果是这样的:

app.get("/meal-plan", async function(req, res) {

  var calorieCount = req.query.calorieCount;
  var mealInput = parseInt(req.query.mealInput);
  var dietInput = req.query.food;
  var goalPerMeal = (calorieCount / mealInput);
  var whichDiet = "diet." + dietInput;

  var breakfastGoal = goalPerMeal;

  function count(query) {
    Food.count(query, function(err, result) {
      if (err) {
        reject(error)
      } else {
        resolve(result)
      }
    });
  }

  function findOne(query, count) {
    return new Promise((resolve, reject) => {
      Food.findOne(query).skip(count).exec(function(err, result) {
        if (err) {
          reject(error)
        } else {
          resolve(result)
        }
      });
    });
  }

  async function getBreakfastArr() {
    let breakfastQuery = {
      "breakfast": true,
      [whichDiet]: true
    };
    let breakfastArr = [];
    while (breakfastGoal >= 150) {
      let count = await count(breakfastQuery);
      let random = Math.floor(Math.random() * count);
      let result = await findOne(breakfastQuery, random);
      breakfastGoal -= result.nutrition.calories;
      breakfastArr.push(result);
    }
    return breakfastArr
  }

  try {
    let breakfastArr = await getBreakfastArr();
    console.log(breakfastArr);

    res.render("meal-plan.ejs", {
      meal: mealInput,
      calories: calorieCount,
      diet: dietInput,
      breakfast: breakfast,
      lunch: lunch,
      dinner: dinner,
      totalCalories: totalCalories
    });

  } catch (e) {
    res.json(e);
  }

});

一些Promise库具有一个称为promisify的函数,该函数将把回调作为最后一个参数的函数作为回调,该函数采用节点样式(err,result)参数,并生成一个函数,该函数在调用时返回promise。 如果可以的话,包装纸会变小很多。 例如, Food.count包装器变为let count = promisify(Food.count); 或者let count = promisify(Food.count.bind(Food));

您从异步函数返回了一个不需要的承诺。 您可以从返回诺言的函数中删除异步。 所以我建议从功能getBreakfastArr()删除异步

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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