1
\$\begingroup\$

I have the following code where I need to return an array of objects as a response that has values from the server. The objects are filled with the right values, but when they are pushed into the array they are pushed before. What's the best way of rewriting this asynchronously?

 router.post('/teacher-schedule',function(req,res){
var teacher_id= req.body.teacher_id,
 school_id= req.body.schoolId,
 array = [], tempo = {};
Schedule.find({school_id:school_id}).then(function(schedules){
 schedules.forEach(function(element){
 ClassSection.findOne({_id:element.class_section_id},function(err,cla){
 if(err){
 console.log(err);
 return res.json({status:"error", message:"error occurred"})
 }else{
 element.entry.forEach(function(entries){
 if( entries.teacher_id==teacher_id){
 tempo = {};
 console.log("tempo fade"+ tempo)
 tempo.class_section = cla.class_title;
 tempo.class_section_code = cla.code;
 tempo.schedule_id =schedules._id ;
 tempo.class_section_id = element._id;
 tempo.subject_id = entries.subject_id;
 console.log("tempo gabel el subject"+ tempo)
 Subject.findOne({_id:entries.subject_id},function(err,subject){
 if(err){
 console.log(err);
 return res.json({status:"error", message:"error occurred"})
 }else{
 tempo.subject_title = subject.title;
 }
 })
 array.push(tempo);// its always an empty value
 }
 })
 }
 })
 });
 res.json({status:"success",message:"successfully returned", records: array})
}).catch(function(err){
 console.log(err);
 res.json({status:"error", message:"error occurred"});
})
});
Peilonrayz
44.4k7 gold badges80 silver badges157 bronze badges
asked Oct 1, 2017 at 21:56
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Direction

With latest version of Ecmascript we get async/await that allow us writing asynchronous code in synchronous style.

Consider an example where function f(...) returns you Promise<F>, and g(...) returns Promise<G>. We can use the following constructions then:

try {
 const resultF = await f();
 const resultG = await g(resultF);
 // keep working with as if we were writing "regular" synchronous code
} catch (anyError) {
 console.error(anyError);
}

This code has to be declared in an async function or arrow function to work. Otherwise, it's still a perfectly asynchronous code...


Sample

In your case, the transformed solution could look similar to this. Please understand this is not 100% working code, because I am not familiar with the particular API of ClassSection that your code deal with. This is more of a sketch to show the direction.

router.post('/teacher-schedule', async (req, res) => {
 const records = [];
 try {
 const schedules = await Schedule.find({school_id : req.body.schoolId});
 schedules.forEach(schedule => {
 ClassSection.findOne(
 { _id: schedule.class_section_id},
 (classSectionSearchError, classSection) => {
 if (err)
 throw new Error(classSectionSearchError);
 schedule.entry.forEach(entryFound => {
 if (entryFound.teacher_id === req.body.teacher_id) {
 const tempo = {
 class_section: classSection.class_title,
 class_section_code: classSection.code,
 schedule_id: schedules._id ,
 class_section_id: schedule._id,
 subject_id: entryFound.subject_id,
 };
 Subject.findOne(
 { _id: entryFound.subject_id},
 (subjectSearchError, subject) =>
 {
 if (subjectSearchError)
 throw new Error(subjectSearchError);
 tempo.subject_title = subject.title;
 }
 );
 records.push(tempo);
 }
 })
 })
 });
 res.status(200).json({ records: records });
 } catch (errorCaught) {
 console.log(errorCaught);
 res.status(500).json({ details: "error occurred: " + JSON.stringify(errorCaught) });
 }
});

Bonus

There's whole lot more potential improvements unrelated to asyncronousity, though.

  • Use === instead of ==, unless you have a strong reason not to follow this advice.
  • Please setup eslint tool -- it's really hard to read the code which is formatted like that.
  • Use const for variable declarations. If something needs to get reassigned, use let. Do NOT use var unless it is necessary (which is super rare the case).
  • If you're using node.js consider using arrow functions.
  • In case of errors set status code to HTTP 500 Internal Server Error, whereas for success use 2XX (they vary depending on scenario).
  • Use proper names. array is too generic. records is actually what's being collected.
  • Use proper names. cla name means nothing to a reader...
  • Logging an object right after creation, but before population is meaningless:

    tempo = {};
    console.log("tempo fade" + tempo)
    
  • Do NOT declare all the variables before actually using them. Always try to achieve joint declaration and assignment: const recordsFound = [].
answered Oct 2, 2017 at 2:15
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Thank you for editing the question, however, you shouldn't edit the formatting of questions, and you shouldn't answer invalidate, where editing the question so that it has good formatting, makes your "Please setup eslint tool" somewhat idiotic - as you made it good. \$\endgroup\$ Commented Oct 2, 2017 at 8:28
  • \$\begingroup\$ in webstorm arrow functions doesnt work, for example ur code produces the following router.post('/teacher-schedule', async (req, res) => { ^ SyntaxError: Unexpected token ( at Object.exports.runInThisContext (vm.js:78:16) at Module._compile (module.js:543:28) \$\endgroup\$ Commented Oct 2, 2017 at 16:37

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.