Open axdyng opened 6 years ago
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.
i did not await for getData(). It is done inside the async function.
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.
@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
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.
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?
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).
Hello @splichte, I'm struggling a bit trying to understand how async/await works. I have the following piece of code:
export const AddExpense = (data) => (dispatch) => {
return axios.post('http://localhost:4000/api/Expenses/', data).then((response) => {
console.log('expid', response.data.id);
let catId = async () => {
let res = await axios
.get('http://localhost:4000/api/Expenses/${id}/getExpenseCategory')
.then((response) => {
return response.data;
});
};
let result = await catId;
console.log('result', result);
debugger;
let data = { ...response.data, ...res.data };
return dispatch({ type: ADD_EXPENSE, payload: data });
});
};
I need the value that returns axios.get to merge it with what the axios.post request returns before dispatching the merged data itself. The issue that I have is that I don't know how to retrieve the axios.get response. Thank you!
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.
I'm sorry I didn't explain it before but I'm glad you still helped me. That worked just as I need it to, thank you! I'll be reading more on the subject to understand it better.
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.
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
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
Hii. I'm begginer and i have this issue when i was trying to connect with Google SpreadSheet: "Promise {
I need to use the data "data.lenght" outside the async function. How can i do it?
` async function accessSpreadsheet() {
await promisify (doc.useServiceAccountAuth)(creds);
const info = await promisify(doc.getInfo)();
const sheet = info.worksheets[0];
const data = await promisify(sheet.getRows)({
query: `data = ${datainput}`
});
return data.length;
}
var total = accessSpreadsheet(); console.log(total); `
The suggested advice by @splichte about reading a tutorial is the best way to go. There's really no way to give short easy answers to a concept that has to be really grasped and understood. Tutorial here
my async function is returning something like this: Promise { 'value' }. I evaluated it and it came up isPending. Is it possible to get a value out of this?
i got it, I needed a .then statement, thx
You need to use await on data, here's my solution:
`(async function load(){ async function getData() { console.log('logging'); const test = await CSVToJSON().fromFile('./data/hans-puns.csv');
return test; } const data = await getData(); })()`
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
I am having the same issue. Can someone tell what am I doing wrong? ` const axios = require('axios');
const ageFinder = async (userName) => {
try {
let userDetails =await axios.get(`https://hacker-news.firebaseio.com/v0/user/${userName}.json`).then(res => res.data.created)
let user =userDetails.data
return user
} catch(err) {
console.log(err.message)
}
}
console.log(ageFinder("someUser"))`
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);
I am also struggling with this seemingly most basic task. I want to call a function that returns some data, assign that data to another variable, and only then continue with execution. I have read the tutorial that @splichte mentioned but it did not address the issue. Consider the code below, based on splichte's suggestion:
async function run() { const data = await asyncFunc(); return data }
console.log('Getting mydata...') mydata = run() console.log('My data is', mydata) process.exit()
When I run this the output is
Getting mydata... mydata is Promise {[[PromiseState]]: 'pending',...
So it hasn't waited for the result, as expected. If I add the await keyword before the call to run() then I get the error "await is only valid in async functions and the top level bodies of modules". I thought that creating the run() function at the top-level was the way to solve that?
Assuming that the function asyncFunc() eventually returns 'Hello World' what code must be written to get the expected output below?
Getting mydata... mydata is Hello World
(P.S. apologies for using Quote instead of Code. The code formatting did not work, running multiple lines together.
Hi,
There seems to be an issue with Async/Await handling. Code below:
const data = getData();
console logging data shows a Promise