0

I am on the newer side to programming; the concept of promises and async/await functionality is something I have had a hard time wrapping my head around. But I know that it is something I should be utilizing in this case.

Background: Building a prototype-banking application with Node, Express, XML2js npm package to parse the XML data that I am working with, XMLhttpRequest, and EJS for templating. I have this get route in my server.js:


    const parseString = require('xml2js').parseString;
    
    app.get('/home', (req, res) => {
     makeCall(`<root>
      <slipped>
        <mail>
          <alike>-1845676614.3625278</alike>
          <paid>uncle</paid>
          <kill>something</kill>
          <name>Stephen<name>
          <men>such</men>
          <firm>rubbed</firm>
          <using>yesterday</using>
        </mail>
      </slipped>
      <pour>-1247721160</pour>
      <poet>language</poet>
      <sets>-1907281866</sets>
      <treated>proper</treated>
      <judge>781679047</judge>
     </root>`)
    //Putting the format of the XML *response* above, to show what I am rendering from
      setTimeout(function () {
        res.render('home.ejs', {
          name: dataList[0].root.slipped.mail.name
        })
      }, 1000);
    }) 

I am wanting to have the app wait and finish makeCall(), before home.ejs gets rendered. If I don't wait, then it will propagate the old value instead. It does work how it is now, but I believe there is a much more efficient way of doing this.

How can I rewrite the above logic using promises or async/await behavior instead of setTimeout?

For reference, the makeCall():


    const makeCall = (call) => {
      myRequest.open('POST', 'http://111.222.3.444:55555')
      myRequest.setRequestHeader('Content-Type', "application/x-www-form-urlencoded");
      myRequest.send(call)
      myRequest.onload = () => {
        if (myRequest.status === 200) {
          parseString(myRequest.responseText, (err, result) => {
            dataList.unshift(result)
          })
        } else {
          console.log('Something went wrong, status code: ' + myRequest.status)
        }
      }
    } 

Thank you in advance for any help you can provide me :)

Hugobop
  • 125
  • 10

2 Answers2

0

Return a promise in makeCall so you can wait for it in your main method. Here is an example

const makeCall = (call) => {
  return new Promise((resolve, reject) => {
    myRequest.open('POST', 'http://111.222.3.444:55555')
    myRequest.setRequestHeader('Content-Type', "application/x-www-form-urlencoded");
    myRequest.send(call)
    myRequest.onload = () => {
      if (myRequest.status === 200) {
        parseString(myRequest.responseText, (err, result) => {
          dataList.unshift(result);
          resolve();
        })
      } else {
        console.log('Something went wrong, status code: ' + myRequest.status)
        reject();
      }
    }
  });
} 

Then you can wait for it to finish to continue in your main method. You can do that by using promises like:

makeCal(...)
.then(() => your_success_logic)
.catch((e) => your_error_logic);

Or you can use async/await like this:

app.get('/home', async (req, res) => {
    await makeCal(...);
    res.render('home.ejs', {
      name: dataList[0].root.slipped.mail.name
    });
});
Pablo Aragon
  • 323
  • 1
  • 8
0

You can make something asynchronous by using the new Promise constructor. It takes a function with two callbacks (resolve,reject). If it fails, reject it. If it's successful you can use resolve. Node 10 and above you can use the async function like so and use the await keyword to wait until a asynchronous function resolves or rejects before moving foward.

const parseString = require('xml2js').parseString;
    
   app.get('/home', async (req, res) => {
    await makeCall(`<root>
     <slipped>
       <mail>
         <alike>-1845676614.3625278</alike>
         <paid>uncle</paid>
         <kill>something</kill>
         <name>Stephen<name>
         <men>such</men>
         <firm>rubbed</firm>
         <using>yesterday</using>
       </mail>
     </slipped>
     <pour>-1247721160</pour>
     <poet>language</poet>
     <sets>-1907281866</sets>
     <treated>proper</treated>
     <judge>781679047</judge>
    </root>`)

   //Putting the format of the XML *response* above, to show what I am rendering from
    res.render('home.ejs', {
      name: dataList[0].root.slipped.mail.name
    })
   }) 

const makeCall = (call) => {
  return new Promise((resolve, reject) => {
    myRequest.open('POST', 'http://111.222.3.444:55555')
    myRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
    myRequest.send(call)
    myRequest.onload = () => {
      if (myRequest.status === 200) {
        parseString(myRequest.responseText, (err, result) => {
          if (err) {
            reject(err)
          } else {
            dataList.unshift(result)
            resolve()
          }
        })
      } else {
        console.log('Something went wrong, status code: ' + myRequest.status)
        reject(new Error(''Something went wrong, status code: ' + myRequest.status'))
      }
    }
  })
}
cWerning
  • 583
  • 1
  • 5
  • 15