node-csvtojson: Async / Await returning Promise instead of values

Hi,

There seems to be an issue with Async/Await handling. Code below:

async function getData() {
  console.log('logging');
  const test = await CSVToJSON().fromFile('./data/hans-puns.csv');

  return test;
}

const data = getData();

console logging data shows a Promise

About this issue

  • Original URL
  • State: open
  • Created 6 years ago
  • Reactions: 21
  • Comments: 22

Most upvoted comments

I think I might have been unclear in my earlier comment. I never wanted you to try to await outside an async function. You can’t do that in current Node. What you need to do is wrap your await call inside an async function, and then call that async function in the top-level of your script. If you just try to immediately use the output of the async function, it isn’t going to be useful, because it’s going to be a Promise. But I think people got the impression that I was suggesting to use the given code as-is but only adding await, which is not what I meant to say at all.

You’re trying to do something like this:

const data = asyncFunc();
console.log(data); // will give you something like Promise { }

You read my comment and understandably thought I meant to do this:

const data = await asyncFunc(); // will error
console.log(data);

What I actually meant was to do this:

async function run() {
  const data = await asyncFunc();
  console.log(data); // will print your data
}

run() // run the async function at the top-level, since top-level await is not currently supported in Node

You don’t need to await on the final run() call, since Node won’t exit until its event loop is empty.

async functions return promises. you need to do const data = await getData() – unless you intend to set data at the top level of the code, in which case you can’t await on getData and need to console.log from inside getData, or log from a different function that calls await getData() inside it.

This is not even an issue. It is simply lack of understanding of async/await. Please someone close this issue. @splichte Kudos for your patience and explanation. A question like this over stack-overflow would have grilled the OP.

I suggest reading a tutorial on async/await, for example: https://medium.com/@_bengarrison/javascript-es8-introducing-async-await-functions-7a471ec7de8a

async functions always return promises.

you need to await to get the value.

async function run() { const data = await asyncFunc(); console.log(data); // will print your data }

run() var result = data // How to assign resultant value to another variable?

How to get the value (data) outside the block to anothe variable? @splichte

As a first note, if you’re struggling to understand how async/await/Promises work (which is fair, they can be confusing at first), it might be a good idea to experiment with simpler functions. the code you’ve sent is fairly dense and has nested lambda functions, mixed Promise-chaining and async/await syntax, calling out to some kind of redux-esque data store, etc. To be honest I find it a little difficult to quickly read and figure out what’s going on.

so a thing to realize is that async/await is a way to avoid Promise-chaining syntax – such as the then statements you’re using, which can produce code that’s difficult to understand. both await and .then() are ways of handling promises. so, you have this code:

		let catId = async () => {
			let res = await axios
				.get('http://localhost:4000/api/Expenses/${id}/getExpenseCategory')
				.then((response) => {
					return response.data;
				});
		};
		let result = await catId;

Right now, it looks like that top-level lambda async () => { } isn’t returning anything. you’re setting let res but then not doing anything with it. Also, that response variable you have in the then() statement is already defined in the outer-scoped axios.post function, which is the type of thing that can cause subtle bugs.

You should be able to do something like this:

// post the data (note I've marked the function async -- it's doing external requests, so it should be asynchronous)
const AddExpense = async (data) => {
    // optimization: await on these functions simultaneously with a Promise.all(), which will be faster.
    const postResponse = await axios.post('http://localhost:4000/api/Expenses/', data);

    const getResponse = await axios.get('http://localhost:4000/api/Expenses/${id}/getExpenseCategory');

    const mergedResponses = { ...getResponse.data, ...postResponse.data };

    return dispatch({ type: ADD_EXPENSE, payload: mergedResponses });
}

the benefit of the async/await syntax is to avoid doing difficult-to-parse Promise-chaining like you’ve done in your example above.

no, it won’t output what you want to myVar, because run is marked async, so it returns a Promise. the main way to force an async function to yield its value is to await on it, which you can only do inside another async function.

you say:

Let`s say, i need to collect data from multiple APIs in paralel, afterwards i need to do some logic on top of collected data. There is no option how to do so?

How you do that is by awaiting on them, then doing the logic inside the async function you’ve defined. like this:

async function run() {
const data = await asyncFunc();
// Your logic goes here.
}

If you have multiple API calls in parallel, you may want to do something like await Promise.all([asyncCall1(), asyncCall2(),...]). This way you don’t have to wait for each function to complete before starting the next. This works because async functions return promises.

You might be under the assumption that at some point you need to “jump” from an async function to a “normal” function for your program to work. You never need to do that. Rather than trying to force the async parts of your program to be synchronous, you should instead incorporate the non-async parts of your program into this async paradigm, which is more in-line with what Node is good at (simultaneous non-blocking tasks).

i did not await for getData(). It is done inside the async function.

For getting something from API:

router.get("/list", async (req, res) => {
  getData = async () => {
    const test = await axios.get("https://jsonplaceholder.typicode.com/posts");
    return test;
  };

  const data = await getData();

  res.send(data.data);
});

In your case you can do something like this:

async function getData() {
  console.log('logging');
  const test = await CSVToJSON().fromFile('./data/hans-puns.csv');
  return test;
}

const data = await getData();
console.log(data);

@splichte I get errors (backed up by documentation) if I attempt to use await outside of an async function. I see some articles claiming you can await anything that returns a promise, without async, but that’s not what I’m seeing with NodeJS & ES8.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await

Hello splichte. Do you want to say, that there is no option how to jump up from async function and load data from async method to some variable for usage in future non-async code? Let`s say, i need to collect data from multiple APIs in paralel, afterwards i need to do some logic on top of collected data. There is no option how to do so?

So in theory: async function run() { const data = await asyncFunc(); //console.log(data); // i don`t want to output anything }

const myVar = run()

Will this load run() output to myVar? I though not, how to achieve that?

async function getData() { console.log(‘logging’); const test = await CSVToJSON().fromFile(‘./data/hans-puns.csv’);

return test; }

if you want to be able to return a value you will have to put an await in front of your function

const data = await getData();

now if you call the function in a get router you have to put an async as follows

router.get('/routerNme,async (req, res) => {

console.log(await getData()) });

I hope that could help you @dysol

getABC(req);

async function getABC(req){

    let A = await getA(req);
    let B = await getB(req);
    let C = await getC(req);
    
}

console.log(‘outside function’)

when i am calling getABC(req) method, it doesn’t wait for the function to be completed. It directly prints outside function. First I want to get all the three values and then it should print outside function