javascriptnode.jsxmlhttprequestejsxml2js

Implement javascript promise or async/await


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 :)


Solution

  • 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
        });
    });