[英]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.