I'm trying to get this function to asynchronously call an API and return the response's JSON. However, the function returns nothing, before the API call has returned and populated res.
I'm confused about the proper usage of asynchronous JavaScript in this use case.
From my understanding, once async has been declared in a function, then the code will pause whenever it hits an await until the await has returned a promise. But that obviously isn't the case. What am I missing?
let queryApi = async (query) => {
const url = "http://localhost:3000/test";
const response = await fetch(url)
const res = await response.json();
return res;
}
Thanks friends!
Yes, that is how Promises work. You must call asynchronous code from an asynchronous setting or a top-level module. So let's say you have the following code (adjusted).
let queryApi = async (query) => {
const response = await fetch(query);
const res = await response.json();
return res;
}
You can call it like so:
let result = await queryApi('https://www.example.com');
console.log(result);
It must be inside an asynchronous function OR in a <script type='module'></script>.
Here you have some problems with your braces.
Actually you need something like this:
const queryApi = async (query) => {
const response = await fetch(query);
const res = await response.json();
return res;
}
Related
I'm still beginner when it comes to JavaScript.
In my vuejs3 app I have the following situation (I assume knowing this is Vue is not important):
In my Vue app I have a method like this
async LoadBasicData()
{
this.basicData = await window.LoadBasicData();
},
It calls a function in a different JavaScript file. The method looks a bit like this:
async function LoadBasicData()
{
return new Promise(resolve =>
{
let result = Object.create(null);
let url = 'MyFancyUrl';
axios
.get(url)
.then((response) =>
{
result.data = response.data;
result = await LoadBuildId(result);
resolve(result);
})
});
}
The LoadBuildId function is looking very similar
async function LoadBuildId(result)
{
return new Promise(resolve =>
{
let url = 'MySecondFancyUrl';
axios
.get(url)
.then((response) =>
{
result.buildId = response.data;
resolve(result);
})
});
}
From my understanding of all this async/await/promise this should be the correct way of doing it, but considering that it's not working I'm pretty sure there is something I have misunderstood
I'm getting the error "await is only valid in async functions and the top level bodies of modules" when calling LoadBuildId. I don't understand the error, as await is called in an async function
What am I doing wrong here? Why can't my async function call another async function? Or is there a better way?
I know there is at least one way to accomplish what I need, that is by using callbacks. I have been using it until now, but I'm not really a fan of it as it really makes the code unnecessary complicated.
You're making 2 mistakes
Wrapping the existing promise-related functionality with your own promise (see: What is the explicit promise construction antipattern and how do I avoid it?)
Mixing async/await with then
The code can be hugely simplified:
async function LoadBuildId(result)
{
let url = 'MySecondFancyUrl';
const response = await axios.get(url)
result.buildId = response.data;
return result;
}
and
async function LoadBasicData()
{
let url = 'MyFancyUrl';
let result = Object.create(null);
const response = await axios.get(url);
result = await LoadBuildId(result);
return result;
}
To be honest, it can be simplified even further - theres no need to be constructing result objects just to set properties on it - you may as well just return the results from a call to axios.get
I want to get a value from an API and save that value for later, but I'm having troubles.
I get the result I want when I use console.log(), but when I do exactly the same thing with "return()" I get this result:
Promise{< resolved >:"The value I want"}
I'll show you my code:
const getDataAA = async () => {
const response = await fetch("https://s3.amazonaws.com/dolartoday/data.json")
const data = await response.json()
console.log("async/await based")
console.log(data.USD.transferencia)
}
When I call getDataAA() I get what I want in the console, but I want to store that value in order to use it, so I changed "console.log(data.USD.transferencia)" for "return(data.USD.transferencia)".
Then I do something like this in order to save the value:
let dolarPrice = getDataAA()
Why when I use "console.log" I get the value but when I use "return" I get also the promise?
const getDataAA = async () => {
const response = await fetch("https://s3.amazonaws.com/dolartoday/data.json")
return response.json()
}
let response = await getDataAA();
console.log(response);
-- EDITED
so this one another example how use it.
the async method (getDataAA) have to return something.
everytime you need to call an async method you have to use await (
if you wait until it's completed)
everytime you use await the method must be async.
<!DOCTYPE html>
<html>
<script type="text/javascript">
var f = async () => {
const getDataAA = async () => {
const response = await fetch("https://s3.amazonaws.com/dolartoday/data.json")
return response.json()
}
let response = await getDataAA();
console.log(response);
}
f();
</script>
</html>
I discovered I way to solve this! I defined a variable outside the function and then the function stored the value I wanted inside that variable. This is my code:
const getDataAA = async () => {
const response = await fetch("https://s3.amazonaws.com/dolartoday/data.json")
const data = await response.json()
console.log("async/await based")
dolarPrice = (data.USD.transferencia)
}
let dolarPrice
getDataAA()
That way I stored the value inside the "dolarPrice" variable. Thanks all the people who answered my question, I found the solution thanks to all of you.
Until now, I thought await makes my program synchronous. However, I see that await only waits for async function to be resolved with a promise then the whole programs continues to run. So, what is the right way to wait & collect the response from async function?
Original code:
let result={
name:'',
country:''
};
const data = await query.getCachedData(did);
result.name = data.name; // undefined
result.country = data.country;//undefined
console.log(result);
I don't know why but awaiting on the async function result works:
let result={
name:'',
country:''
};
const data = await query.getCachedData(did);
result.name = await data.name; //'Jon'
result.country = await data.country;// 'US'
console.log(result);
But I am not sure if this is the solution.
Since getCachedData returns the promise, I thought this may be the right way but the then()/catch() didn't execute.
query.getCachedData(did).then((tfnData) => {
result.name = data.name;
result.country = data.country;
console.log(result);
}).catch((dbError) => {
console.log(dbError);
});
Can anyone correct me to get the result the right way?
A Promise is the return from a async function. The result is maybe not finish yet.
That is why you can await a method (like you did it). This will set the return from the function when the calculation is complied.
Or you can make use of 'then':
const data1 = await query.getCachedData(did);
//data1 has a value at this point of code
const data2;
query.getChachedData(did).then((result)=>{data2 = result});
//data2 can have a value or will get one later (this is async) at this point of code
With Promise all you can let multiple methods run asynchronous and wait for all at once.
https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
const callStack = [];
const data1;
const data2;
callStack.push(query.getChachedData(did).then((result)=>{data1 = result}));
callStack.push(query.getChachedData(did).then((result)=>{data2 = result}));
//run both query Methods at asynchronous
await Promise.all(callStack);
//data1 and data2 hava a value at this point of code
Until now, I thought await makes my program synchronous
Async/await makes the code to looks like synchronous, but behind is just syntactic sugar for promises in Javascript. Really? Yes
Is just return thePromise().then(result => result)
I see that await only waits for async function to be resolved with a promise then the whole programs continues to run
When you work with promises, they not make Node.js code run synchronous, in the other hand, promises allow you to write flows that appear synchronous.
So, what is the right way to wait & collect the response from async function?
According to your example, the code will be something like this:
const queryResult = did => query.getCachedData(did).then(tfnData => tfnData);
// Without async/await
queryResult(did)
.then(data => {
const { name, country } = data;
const result = { name, country };
console.log(`${result.name}, ${result.country}`); // Jon, US
})
.catch(error => console.log(`Error produced: ${error}`));
// With async/await
(async () => {
try {
// ... Some other code ....
// ... Some other code ....
// ... Some other code ....
const data = await queryResult(did);
const { name, country } = data;
const result = { name, country };
console.log(`${result.name}, ${result.country}`); // Jon, US
} catch (error) {
console.log(`Error inside try-catch: ${error}`);
}
})();
You are correct that await waits for an async function to return a promise. For your code example, I would suggest the following:
let result={
name:'',
country:''
};
async function getData() {
const data = await query.getCachedData(did);
result.name = data.name; // 'Jon'
result.country = data.country; // 'US'
console.log(result);
}
await can only be used inside an async function. It will pause the function until a promise is received from query.getCachedData(), save that response into const data which can then be used to set the name and country of the result object. You can also look at the MDN docs for both async and await.
await does not make your asynchronous code synchronous - and there should not be any reasonable reason to do so ... behind the scenes it returns a promise and chain it with then instead of you having to chain it with then yourself.
What you did with the then keyword, is what the await did for you.
You can use whatever suits you, but async/await makes your code easier to read.
if this works
result.name = await data.name;
this means that the name is an async getter function that you have to await for it to get the result. You can do it also like this
data.name.then(name => doWhateverYouWantWithName(name)) or using the await keyword like you already did - and that should be better even.
I realise very similar questions have been answered before, but I'm still finding it very confusing as to how this works...
From my understanding promises are used to deal with asyc requests - these promises essentially send back the state or a "promise" that at some point later a JSON body (or other object) will be delivered.
What I'm trying to understand is how I properly handle these requests so that the function doesn't return until the JSON body is ready to be parsed.
Below I'm trying to simply extract the key "result" (which returns a string "result") and parse it to another variable that can be stored and then later used somewhere else in my code. Unfortunately, my code always returns a [Object Promise], rather than the extracted JSON. I believe this is because response.json is also a promise... however, I don't understand how I get out of the "chain of promises" and return a value that I can actually do something with.
Thanks for any advice,
async function name() {
const response = await fetch('https://xxxxx.herokuapp.com/timespent', {});
const json = await response.json();
return json.result;
}
let varr = name();
console.log(varr)
Since your function is async it always return a promise. You need to use await for result.
read more about async here
async function name() {
const response = await fetch('https://mautargets.herokuapp.com/timespent', {});
const json = await response.json();
return json.result;
}
async function result(){
//await can only be called from inside of async function. So we need async function for await name()
let varr = await name();
console.log(varr) // Success
}
result()
In your example code, name function is declared async, so it returns a promise.
Inside that function body, you correctly handle async calls like fetch or the JSON transformation.
What you need now is either use await to wait for the function to "resolve", or use the "older" then/catch promises methods. Note that you cannot always use await outside an async function so you may need to wrap it.
Example :
async function name() {
const response = await fetch('https://mautargets.herokuapp.com/timespent', {});
const json = await response.json();
return json.result;
}
// using promise.then
name().then(result => console.log(result));
// wrapping await
(async function test() {
try{
console.log(await name());
}catch(error) {
// error goes here if promise got rejected
}
})()
You could have a callback in the function declaration, and use '.then(...)' and call it when the promise has been resolved:
async function name(cb) {
const response = await
fetch('https://mautargets.herokuapp.com/timespent', {});
const json = response.json();
json.then(x => cb(x))
}
name(console.log)
This is because you're using an Async function, which will return a promise.
Or if you would like the method to return, you could either call it in another Asynchronous context and utilize await again:
// Assume no callback: code just as you had it.
async function wrapper() {
console.log(await name())
}
Or you could do name().then(...) as specified before:
// Assume no callback: code just as you had it.
name().then(console.log)
Hope this helps!
I'm actually looking for the answer(same as yours), so I found this way.
I. ASK/REQUEST for data
async function fetchMyJson() {
const response = await fetch('https://1stAPI.devdeveloper1.repl.co/fiveD');
const myData = await response.json();
return myData;
}
II.GET Extract data
fetchMyJson().then(myData => {
let myData_output = myData.USD[0].rate; // fetched or Get OUTPUT data
console.log(myData_output);
document.body.innerHTML = `<div>${myData_output}</div>`; //make sure you add ${} for output
});
async function fetchMyJson() {
const response = await fetch('https://1stAPI.devdeveloper1.repl.co/fiveD');
const myData = await response.json();
return myData;
}
//GET Extract data
fetchMyJson().then(myData => {
let myData_output = myData.USD[0].rate; // fetched or Get OUTPUT data
console.log(myData_output);
document.body.innerHTML = `<div>${myData_output}</div>`; //make sure you add ${} for output
});
It is correct that you await fetch and .json since they are async.
async function name() {
const response = await fetch('http://blah.com/api', {});
const json = await response.json();
return json.result;
}
However, async and Promises inside function name make it async too. So the return value of name is a Promise that you should await it, or .then it, like:
// Old style .then
name().then(result => console.log(result))
// Modern style await
async function main() {
const result = await name()
console.log(result)
}
According to this article: https://medium.com/#bluepnume/learn-about-promises-before-you-start-using-async-await-eb148164a9c8
It seems like it could be possible to use below syntax:
let [foo, bar] = await Promise.all([getFoo(), getBar()]);
for multiple promises execution. However while using it I get Uncaught SyntaxError: Unexpected identifier.
How can i use async/await and promise.all to achieve multiple simultaneous operations executed and one resolve with a response.
-----EDITED
the function i am using inside promise.all is this one:
async function getJson(callback) {
try {
let response = await fetch('URL_LINK_HERE');
let json = await response.json();
return json;
} catch(e) {
console.log('Error!', e);
}
}
as a test field i am using google chrome Version 60.0.3112.113
Most likely your code looks something like this:
var thingsDone = await Promise.all([
Promise.resolve("eat"),
Promise.resolve("sleep")
]);
console.log(thingsDone);
This will not work because the await keyword is only valid within an async function (which the global context is not). It will simply cause a syntax error.
One way to handle this is to use it like a regular old promise and not using the await keyword:
Promise.all([
Promise.resolve("eat"),
Promise.resolve("sleep")
]).then((thingsDone) => console.log(thingsDone));
Or if you want to get fancy (or need more room to write an expressive function), wrap your logic in an async function and then handle it like a promise:
async function doThings() {
var eat = await Promise.resolve("eat");
var sleep = await Promise.resolve("sleep");
return Promise.all([Promise.resolve(eat), Promise.resolve(sleep)]);
}
doThings().then((thingsDone) => console.log(thingsDone));
This would allow you to use await as needed and is much more helpful in a more complicated function.
Or even more succinctly using an immediately-executing async function:
(async() => {
var eat = await Promise.resolve("eat");
var sleep = await Promise.resolve("sleep");
return Promise.all([Promise.resolve(eat), Promise.resolve(sleep)]);
})().then((thingsDone) => console.log(thingsDone));
torazaburo pointed me to right direction in his comments and i figured it out, this is the final code that is working:
var getJson = async function() {
try {
let response = await fetch('http://mysafeinfo.com/api/data?list=englishmonarchs&format=json');
let json = await response.json();
return json;
} catch(e) {
console.log('Error!', e);
}
}
var check_all = async function(callback) {
callback( [foo, bar] = await Promise.all([getJson(), getJson()]) );
};
check_all(function(data) {
console.log(data);
});
This works, example here: https://jsfiddle.net/01z0kdae/1/