Reputation: 3
I'm trying to learn about async
/await
and Promise functions. However after a lot of effort and research, I cannot find any simple way to get a proper way to use my 4 for loops.
I give you the code how it's supposed to be if Javascript if it wouldn't be asynchronous. Can you tell me where (and how) can I put promises to get my code to work as intended?
function (courses) {
var lines = [];
for (var i = 0; i < courses.length; i++) {
var course = courses[i];
var sessions = course.sessions;
var students = course.students;
var skills = course.skills;
console.log('\nCourse : ' + course);
for (var j = 0; j < sessions.length; j++) {
var session = sessions[j];
console.log('\nSession : ' + session);
for (var k = 0; k < students.length; k++) {
var student = students[k];
console.log('\nStudent : ' + student);
for (var l = 0; l < skills.length; l++) {
var skill = skills[l];
console.log('\nSkill : ' + skill);
Evaluation.findOne({
student_id: student._id,
session_id: session._id,
skill_id: skill._id
}).exec(function (err, eval) {
console.log('\nStudentID : ' + eval);
console.log('\nSessionID : ' + eval);
console.log('\nSkillID : ' + eval);
console.log('\nEval : ' + eval);
var line = [];
line.push(course.name);
line.push(session.date);
line.push(student.firstname);
line.push(student.name);
if (eval) {
line.push(eval.name);
line.push(eval.mark);
}
else {
line.push(skill.name);
line.push('Not Evaluated');
}
lines.push(line)
})
}
}
}
}
return lines;
}
Upvotes: 0
Views: 56
Reputation: 1
It looks like you're trying to do two things here: you want to asynchronously loop through courses/sessions/students/skills and do a fairly time-intensive Evaluation.findOne
call.
I recommend replacing some or all of your for loops with async.forEach
. You could also put the Evaluation.findOne
block into a helper function wrapped in a Promise
, but given that it's pushed into lines
after it's executed it's an optional move.
Do something like this: the skills iteration now uses async.forEach and the line builder is in a promise.
function (courses) {
var lines = [];
for (var i = 0; i < courses.length; i++) {
var course = courses[i];
var sessions = course.sessions;
var students = course.students;
var skills = course.skills;
console.log('\nCourse : ' + course);
for (var j = 0; j < sessions.length; j++) {
var session = sessions[j];
console.log('\nSession : ' + session);
for (var k = 0; k < students.length; k++) {
var student = students[k];
console.log('\nStudent : ' + student);
skills.forEach(function(skill) {
console.log('\nSkill : ' + skill);
buildStudentLine(student, session, skill, course)
.then((line )=> {
lines.push(line);
})
.catch((error) => {
console.log(error);
})
});
}
}
}
return lines;
}
function buildStudentLine(student, session, skill, course) {
return new Promise((resolve, reject) => {
Evaluation
.findOne({
student_id: student._id,
session_id: session._id,
skill_id: skill._id
})
.exec(function (err, evaluated) {
var line = [];
line.push(course.name);
line.push(session.date);
line.push(student.firstname);
line.push(student.name);
if (evaluated) {
line.push(evaluated.name);
line.push(evaluated.mark);
} else {
line.push(skill.name);
line.push('Not Evaluated');
// possibly put this in here if you don't want the line to enter the lines array:
// reject('Not Evaluated');
}
resolve(line);
});
});
}
Upvotes: 0
Reputation: 664297
Assuming that you use mongoose, all you need to change is replacing
Evaluation.findOne({ student_id: student._id, session_id: session._id, skill_id: skill._id }).exec(function (err, eval) { console.log('\nStudentID : ' + eval); console.log('\nSessionID : ' + eval); console.log('\nSkillID : ' + eval); console.log('\nEval : ' + eval); var line = []; line.push(course.name); line.push(session.date); line.push(student.firstname); line.push(student.name); if (eval) { line.push(eval.name); line.push(eval.mark); } else { line.push(skill.name); line.push('Not Evaluated'); } lines.push(line) })
by
const eval = await Evaluation.findOne({
// ^^^^^
student_id: student._id,
session_id: session._id,
skill_id: skill._id
});
console.log('\nStudentID : ' + eval);
console.log('\nSessionID : ' + eval);
console.log('\nSkillID : ' + eval);
console.log('\nEval : ' + eval);
var line = [];
line.push(course.name);
line.push(session.date);
line.push(student.firstname);
line.push(student.name);
if (eval) {
line.push(eval.name);
line.push(eval.mark);
} else {
line.push(skill.name);
line.push('Not Evaluated');
}
lines.push(line)
as all methods return promise-like objects already that you can directly await
, instead of using exec
and passing a nodeback.
Upvotes: 1