Home > Software design >  Getting 'undefined' from asynchronous response despite 'await' and 'then�
Getting 'undefined' from asynchronous response despite 'await' and 'then�

Time:06-12

I'm trying to send a GET request, parse its response and return it to another method. Apparently I have problems handling the asynchronous response.

I want to use Node.js' standard modules, so no Axios.

// class 1: Calling API, processing and returning the response

export async function getData() {
  let str = '';

  const options = {
    hostname: 'jsonplaceholder.typicode.com',
    path: '/posts/',
    method: 'GET',
    json: true,
  };

  https
    .get(options, response => {
      response.on('data', chunk => {
        str  = chunk;
      });

      response.on('end', () => {
        return parseJson(str);
      });
    })
    .on('error', error => {
      console.log(error);
    });
}

async function parseJson(str) {
  const json = JSON.parse(str);
  var text;
  try {
    json.forEach(element => {
      text  = element.body;
    });
    // console.log(text); // I'm getting the expected output
    return text;
  } catch (error) {
    console.log('error');
  }
}


// class 2: Calling the 2 methods above

getData().then(function (value) {
  console.log('DATA: '   value); // this is called first
});

Unfortunately as output I get an undefined. Despite using async and then:

DATA: undefined

CodePudding user response:

Change getData as follows

export function getData() {
    return new Promise((resolve, reject) => {
        let str = '';

        const options = {
            hostname: 'jsonplaceholder.typicode.com',
            path: '/posts/',
            method: 'GET',
            json: true,
        };

        https.get(options, response => {
            response.on('data', chunk => {
                str  = chunk;
            });

            response.on('end', () => {
                try {
                    const result = parseJson(str);
                    resolve(result);
                } catch (error) {
                    reject(error);
                }
            });
            response.on('error', reject);
        })
        .on('error', reject);
    });
}

Now it returns a Promise, which resolves to the result of parseJson(str) or rejects with the error at on('error'

And parseJson as follows - doesn't need to be async since there's nothing asynchronous about the code inside it

Also, removing the try/catch in parseJson and using try/catch in .on("end" means that you can reject the promise returned by getData if there's an error in the parseJson call

function parseJson(str) {
    const json = JSON.parse(str);
    let text = '';
    json.forEach(element => {
        text  = element.body;
    });
    return text;
}

alternatively (IMHO better)

function parseJson(str) {
    const data = JSON.parse(str); // call it data, not json
    return data.map(({body}) => body).join('');
}

or even

const parseJson = (str) => JSON.parse(str).map(({body}) => body).join('');

But that's not important :p

CodePudding user response:

You didn't return anything in the getData. Try this

export async function getData() {
  let str = '';

  const options = {
    hostname: 'jsonplaceholder.typicode.com',
    path: '/posts/',
    method: 'GET',
    json: true,
  };

 return https
    .get(options, response => {
      response.on('data', chunk => {
        str  = chunk;
      });

      response.on('end', () => {
        return parseJson(str);
      });
    })
    .on('error', error => {
      console.log(error);
    });
}
  • Related