我正在尝试在异步函数中使用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。 Async函数从我的数据库中找到一个随机配方,并将其添加到我的数组breakfastArr中。找到食谱后,它将从BreakfastGoal中减去该食谱的卡路里计数。
我希望此功能一直运行到breakfastGoal减少到150以下;但是,它似乎不起作用。如果删除While循环,该函数将成功找到早餐项目,将其添加到数组中,并从breakfastGoal中减去其卡路里计数。打破它的唯一一件事就是添加While循环。
这与resolve()有关吗?在异步功能中,还是我缺少重要的东西?
非常感谢您的帮助。
答案 0 :(得分:1)
您认为这样的事情行得通吗?我还没有测试。只是一个主意。 将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);
}
});
}
})
}
答案 1 :(得分:0)
问题是您只创建一个诺言,但是在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
函数应返回该数组,因此不必在顶部定义它。
答案 2 :(得分:0)
这里的问题是,您正在混合使用回调函数和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));
答案 3 :(得分:-3)
您从异步函数返回了一个不需要的承诺。您可以从返回诺言的函数中删除异步。 所以我建议从功能getBreakfastArr()中删除异步