1

I am trying to send message through an API using a function. When function do his duty it returns back a value which is messageLodId and it needs to be updated at Attendence in main loop. But when I execute this code, value comes undefined.

There are two questions:

1) Is the structure right?

2) If yes, please provide the answer for this problem.

//Posting SMS 
router.post('/sms/', async function(req, res) {
    let attendenceRecordId = parseInt(req.body.attendenceRecordId);
    let result = await AttendenceRecord.findOne({where: {id: attendenceRecordId }, include: [ {model: Attendence, include: [{model: Student}
    ]}, {
        model: Class
    }], order: [['date', 'DESC']]});

    if(!result) {
        res.sendStatus(404); 
    }

    for await (let attendence of result.attendences){

        let messageLogId = await sendSMS(attendence); 

        console.log("Message ID: ", messageLogId); 
        Attendence.update(
            { smsLogId: messageLogId },
            { where: { id: attendence.id  } }
          ); 
    }

    AttendenceRecord.update(
        { isMessageSent:true },
        { where: { id: result.id } }
      ); 

    res.send({messageSent: true});

});


Here is the function definition. Right now I am just returning 1.

In real world the URL returns a code.

async function sendSMS(attendence){

    //console.log(target);


    setTimeout(function(){
        let message = `Respected Parent, your son/daughter ${attendence.student.name} is absent on ${attendence.date}`;
        let messageURL = encodeURI(message); 
        let api = 'SOME VALUE';
        let phone = attendence.student.fphone.substring(1, 11); 
        let target = `http://BASE_URL/api.php?key=${api}&receiver=92${phone}&sender=DigitalPGS&msgdata=${messageURL}`; 

        return 1; 
    }, 2000); 


}
Jaspreet kaur
  • 630
  • 5
  • 19
Yasir Shahzad
  • 47
  • 1
  • 9
  • `sendSMS` doesn't return anything, so you will get `undefined` – Keith Aug 27 '19 at 11:18
  • The function `sendSMS` does not return anything. Only the callback for `setTimeout` has an return statement. – Nijeesh Joshy Aug 27 '19 at 11:19
  • 1
    To add: `for await` is not needed, u're already awaiting the results above. And have a look [how to wrap setTimeout in a promise & return one](https://stackoverflow.com/questions/22707475/how-to-make-a-promise-from-settimeout) – ambianBeing Aug 27 '19 at 11:19
  • But results are response also comes quickly. I mean it is not delaying like I delayed for 2 second for each iteration. – Yasir Shahzad Aug 27 '19 at 11:25

3 Answers3

0

You should return promise from sendSMS. Resolve promise in setTimeout callback function.

function sendSMS(attendence){

    //console.log(target);
   return new Promise((resolve, reject) => {
   setTimeout(function(){
        let message = `Respected Parent, your son/daughter ${attendence.student.name} is absent on ${attendence.date}`;
        let messageURL = encodeURI(message); 
        let api = 'SOME VALUE';
        let phone = attendence.student.fphone.substring(1, 11); 
        let target = `http://BASE_URL/api.php?key=${api}&receiver=92${phone}&sender=DigitalPGS&msgdata=${messageURL}`; 

        resolve(1); 
    }, 2000); 
   });

}
Jitesh Manglani
  • 495
  • 5
  • 12
  • Also let me know, now function is responding after few seconds like I set timeout value. If in future, I send the request to this URL to send SMS. URL will take sometime to response then this function will work? – Yasir Shahzad Aug 27 '19 at 11:31
  • @YasirShahzad Your `setTimeout` is a bit of a red herring here. Whatever your going to use to send the SMS, if it's going to be a promise, just return it. If it's not a promise make it into one. Using a Promise constructor and a setTimeout makes no sense here. – Keith Aug 27 '19 at 11:35
  • What if the async function takes more than 2 secs to finish?? This won't work and this actually isn't the right approach to handle async functions in loop. You should use async/await and for..of to get the desired result. – Mohammed Amir Ansari Aug 27 '19 at 12:07
0

You should have sendSMS return a promise, and await that:

exec();

async function exec()
{
  var records = [1,2,3];

  for(var i=0;i<records.length;i++)
  {
     var messageLogId = await sendSMS(records[i]);
     console.log("Result received from resolve", messageLogId);
  }
}

function sendSMS(record)
{
    // simulate an async method:
    return new Promise(function(resolve, reject) {
      setTimeout(function() {
        console.log("Send sms for record", record);
        resolve(1);
      }, 1000);
    });
}

Note that the setTimeout here is just to demonstrate an asynchronous action. In the real world your sendSMS function will no doubt call an API, which will itself be asynchronous - just return the promise from that (or, wrap the call in a promise if the API client doesn't return one).

Jamiec
  • 133,658
  • 13
  • 134
  • 193
0

First, make your function Promisify. Then chunk your function and call that function in the for loop and handle with Promise.all().

const manyPromises = [];

for (const attendence of result.attendences) {
  manyPromises.push(sendSmsAndUpdateStatus(attendence));
}
// Execution wait until all promises fulfilled/rejected
const result = await Promise.all(manyPromises);

const sendSmsAndUpdateStatus = async (attendence) => {
  try {
    const messageLogId = await sendSMS(attendence);
    const updateObj = { smsLogId: messageLogId };
    const condition = { where: { id: attendence.id } };
    const result = await Attendence.update(updateObj, condition);
    return { result, messageLogId };
  } catch (err) {
    logger.error(err);
    throw err;
  }
};
const sendSMS = (attendence) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      const message = `Respected Parent, your son/daughter ${attendence.student.name} is absent on ${attendence.date}`;
      const messageURL = encodeURI(message);
      const api = 'SOME VALUE';
      const phone = attendence.student.fphone.substring(1, 11);
      const target = `http://BASE_URL/api.php?key=${api}&receiver=92${phone}&sender=DigitalPGS&msgdata=${messageURL}`;
      return resolve(1);
    }, 2000);
  });
};

Summary make sure your function sendSMS will return Promise, afterwards you can handle it with async/await or .then().catch() approaches.

Neel Rathod
  • 2,013
  • 12
  • 28