Fegr Gree
Fegr Gree

Reputation: 3

Cannot figure Async/Await and Promises to work

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

Answers (2)

K Furuya
K Furuya

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

Bergi
Bergi

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

Related Questions