So here's my code for now:
function geoPerformAction(e) {
getGeoApiData(document.getElementById('zipPostCode').value)
.then((APIarr) => {
postGeoData('/geoadd', { Lat: APIarr[0] });
})
.then(function () {
updateUIGeo();
})
}
//Friend helped with me with get API data
/* Function to GET Web API Data*/
const getGeoApiData = async ( place) => {
const response = await fetch("https://pokeapi.co/api/v2/pokemon/" + place + "/");
try {
const webData = response.json();
const Pla = webData;
console.log(Pla);
const APIarr = [Pla];
return APIarr;
}
catch (error) {
console.log("error", error);
}
}
Everytime I use this, the webdata variable is undefined. Why is this happening? Why isn't returning the data that I requested for?
Thank you.
You are not awaiting for the second promise to be resolved
const webData = await response.json();
Example:
async function fetchAsync () {
// await response of fetch call
const response = await fetch('https://api.github.com');
// only proceed once promise is resolved
const data = await response.json();
// only proceed once second promise is resolved
return data;
}
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 11 months ago.
I found different solutions here, but none worked for me. I have this simple code:
const Element = () => {
async function getEndData() {
const data = (await getEnd());
return data;
}
}
const getEnd = async () => {
return await axios.get('http://localhost:8080/end').then(res => res.data);
}
And it always return a Promise "pending" with inside a [[PromiseResult]] with the value i need, when i call getEndData().
I tried also to call directly getEnd() removing the then(), returning only the data, but nothing. If i print res.data in console.log, it will return the right value i need.
this should work:
const Element = () => {
async function getEndData() {
const data = await getEnd();
return data;
}
}
const getEnd = async () => {
const response = await axios.get('http://localhost:8080/end');
return response;
}
I'm not sure you are doing it the right way. You can try this:
const Element = () => {
return async function getEndData() {
const data = await getEnd();
return data;
}
}
const getEnd = () => {
return new Promise((resolve, reject) => {
axios.get('http://localhost:8080/end')
.then(res => {
resolve(res.data)
})
.catch(err => {
reject(err);
})
})
}
Also, What is the use of element function if you are not returning anything.
your getEndData() in returning a promise . add await or then where ever you are receiving the getEndData() response .
// const Element = () => {
async function getEndData() {
const data = (await getEnd());
return data;
}
// }
const getEnd = async () => {
return await axios.get('http://localhost:8080/end').then(res => res);
}
async function callEndData(){
let x = await getEndData()
console.log(x)
}
callEndData()
since it is returning promise and you are not using await or then it is showing promise pending
why do you need Element() ?
In case you need to call ELement function and also wants the data part of response you can try like this .
const Element = async() => {
async function getEndData() {
return await getEnd();
}
let fromEndData = await getEndData()
return fromEndData
}
const getEnd = async () => {
return axios.get('http://localhost:8080/end').then(res => {
return res.data
});
}
async function callEndData(){
let x = await Element()
console.log(x)
}
callEndData()
in console.log(x) i am getting the value being passed .
I have this test I made just to check an API, but then i tryied to add an URL from a second fetch using as parameter a value obtained in the first fetch and then return a value to add in the first fecth. The idea is to add the image URL to the link. thanks in advance.
function script() {
const url = 'https://pokeapi.co/api/v2/pokemon/?offset=20&limit=20'
const result = fetch(url)
.then( (res)=>{
if(res.ok) {
return res.json()
} else {
console.log("Error!!")
}
}).then( data => {
console.log(data)
const main = document.getElementById('main');
main.innerHTML=`<p><a href='${data.next}'>Next</a></p>`;
for(let i=0; i<data.results.length;i++){
main.innerHTML=main.innerHTML+`<p><a href=${getImageURL(data.results[i].url)}>${data.results[i].name}</a></p>`;
}
})
}
async function getImageURL(imgUrl) {
const resultImg = await fetch(imgUrl)
.then( (res)=> {
return res.json()
})
.then (data => {
console.log(data.sprites.other.dream_world.front_default);
})
return resultImg.sprites.other.dream_world.front_default;
}
In general, don't mix .then/.catch handlers with async/await. There's usually no need, and it can trip you up like this.
The problem is that your fulfillment handler (the .then callback) doesn't return anything, so the promise it creates is fulfilled with undefined.
You could return data, but really just don't use .then/.catch at all:
async function getImageURL(imgUrl) {
const res = await fetch(imgUrl);
if (!res.ok) {
throw new Error(`HTTP error ${res.status}`);
}
const resultImg = await res.json();
return resultImg.sprites.other.dream_world.front_default;
}
[Note I added a check of res.ok. This is (IMHO) a footgun in the fetch API, it doesn't reject its promise on HTTP errors (like 404 or 500), only on network errors. You have to check explicitly for HTTP errors. (I wrote it up on my anemic old blog here.)]
There's also a problem where you use getImageURL:
// Incorrent
for (let i = 0; i < data.results.length; i++) {
main.innerHTML=main.innerHTML+`<p><a href=${getImageURL(data.results[i].url)}>${data.results[i].name}</a></p>`;
}
The problen here is that getImageURL, like all async functions, returns a promise. You're trying to use it as those it returned the fulfillment value you're expecting, but it can't — it doesn't have that value yet.
Instead, you need to wait for the promise(s) youre creating in that loop to be fulfilled. Since that loop is in synchronous code (not an async function), we'd go back to .then/.catch, and since we want to wait for a group of things to finish that can be done in parallel, we'd do that with Promise.all:
// ...
const main = document.getElementById('main');
const html = `<p><a href='${data.next}'>Next</a></p>`;
Promise.all(data.results.map(async ({url, name}) => {
const realUrl = await getImageURL(url);
return `<p><a href=${realUrl}>${name}</a></p>`;
}))
.then(paragraphs => {
html += paragraphs.join("");
main.innerHTML = html;
})
.catch(error => {
// ...handle/report error...
});
For one, your
.then (data => {
console.log(//...
at the end of the promise chain returns undefined. Just remove it, and if you want to console.log it, do console.log(resultImg) in the next statement/next line, after await.
This the final version that accomplish my goal. Just want to leave this just in case someone finds it usefull. Thanks for those who answer!
function script() {
const url = 'https://pokeapi.co/api/v2/pokemon/?offset=20&limit=20'
const result = fetch(url)
.then( (res)=>{
if(res.ok) {
return res.json()
} else {
console.log("Error!!")
}
}).then( data => {
console.log(data)
const main = document.getElementById('main');
main.innerHTML=`<p><a href='${data.next}'>Proxima Página</a></p>`;
Promise.all(data.results.map(async ({url, name}) => {
const realUrl = await getImageURL(url);
return `<div><a href=${realUrl}>${name}</a></div>`;
}))
.then(paragraphs => {
main.innerHTML=main.innerHTML+paragraphs;
})
.catch(error => {
console.log(error);
});
})
}
async function getImageURL(imgUrl) {
const res = await fetch(imgUrl);
if(!res.ok) {
throw new Error(`HTTP Error ${res.status}`)
}
const resultImg = await res.json();
return resultImg.sprites.other.dream_world.front_default
}
I am trying to get some data from an API but I'm recieving promises instead of data
const fetchCoordinatesFromAdress = async (adress: any) => {
let response = {}
try {
response = await MapBoxAPIService.getCoordinatesFromAdress(adress)
} catch (e) {
console.warn(e)
}
return response.data
}
if I console log response.data I get the data but I want to return the data and then it just returns the promise
Call it with await or .then()
Example:
const data = await fetchCoordinatesFromAdress(address);
or
fetchCoordinatesFromAdress(address).then((data) => ...)
ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
My code is violating the eslint rule no-async-promise-executor but I'm not sure how to refactor it so that it doesn't have the async in the new Promise(async (resolve, reject) => {});. My code is full of these and I guess it causes errors to bot be caught so I could use some help understanding how to approach this better.
Here's an exampe function:
updateUser = () => {
return new Promise(async (resolve, reject) => {
try {
const url = "/getUser";
const response = await fetch(url);
if (response.ok) {
const user = await response.json();
//
// Do something with user object...
//
} else {
console.log("response", response);
window.location = "/admin";
}
resolve();
} catch (error) {
console.log("error: ", error);
reject(error);
}
});
};
when you mark the function as async, it will automatically wrap the return value inside a promise, whatever you return from the function... it will get passed to .then() and whatever is thrown inside a async function will get passed to your error handler such as .catch()
here is a example of what you could do.
const updateUser = async () => {
const url = "/getUser";
let response;
try {
response = await fetch(url);
} catch (error) {
throw new Error(error);
}
return response;
}
you can also reference the global promise explicit to return or reject values inside a async function.
const updateUser = async () => {
const url = "/getUser";
let response;
try {
response = await fetch(url);
} catch (error) {
Promise.reject(error);
}
return Promise.resolve(response);
}
async functions always return promises.
By wrapping your anonymous async function in new Promise(...) you are creating a Promise which only and always adopts the promise returned by the async function.
Just get rid of the wrapper, replace your resolve calls with return and your reject with throw.
updateUser = async () => {
try {
const url = "/getUser";
const response = await fetch(url);
if (response.ok) {
const user = await response.json();
//
// Do something with user object...
//
} else {
console.log("response", response);
window.location = "/admin";
}
} catch (error) {
console.log("error: ", error);
throw error;
}
};
What I am trying to accomplish in a Firebase Function:
Read from Firebase database email addresses to batch email.
Loop through each one and send out emails.
I am having an issue with closing promises I believe. These don't need to be ran in order, I just need to resolve all promises before ending.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const https = require('axios');
exports.sendEmail = functions.pubsub.topic('nightly_topic').onPublish(() => {
let emailsToSend = [];
async function getTests (){
admin.firestore()
.collection("tests")
.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
emailsToSend.push(doc.data())
});
})
.catch(function (error) {
console.error(error);
});
}
async function send (address){
let body = {
//MANDRILL INFO REMOVED
};
let endpoint = 'https://mandrillapp.com/api/1.0/messages/send-template.json';
https.post(endpoint, body)
.then((result) => {
console.log('SUCCESS');
})
.catch(function (error) {
console.error(error);
});
}
async function init() {
await getTests();
for (const email of emailsToSend) {
await send(email.address);
}
}
init();
});
You're missing return statements from your functions.
return https.post(... etc
Try this:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const https = require('axios');
exports.sendEmail = functions.pubsub.topic('nightly_topic').onPublish(() => {
let emailsToSend = [];
function getTests (){
return new Promise((resolve, reject) => {
admin.firestore()
.collection("tests")
.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
emailsToSend.push(doc.data())
});
resolve(emailsToSend);
})
.catch(function (error) {
reject(error)
});
});
}
async function send (address){
let body = {
//MANDRILL INFO REMOVED
};
let endpoint = 'https://mandrillapp.com/api/1.0/messages/send-template.json';
https.post(endpoint, body)
.then((result) => {
console.log('SUCCESS');
})
.catch(function (error) {
console.error(error);
});
}
async function init() {
const emailsToSend = await getTests();
for (const email of emailsToSend) {
await send(email.address);
}
}
init();
});
It might help you.
so you are almost there. The issue is that you are not returning anything. You should fix it by just doing:
Return Promise
// code ...
exports.sendEmail = functions.pubsub.topic('nightly_topic').onPublish(() => {
// code
return init();
}
Use async
// code ...
exports.sendEmail = functions.pubsub.topic('nightly_topic').onPublish(async () => {
// code
await init();
}
Note: an async function always returns a Promise.
Suggestion
In your code, you are sending emails one at a time. await send(email.address); This line of code waits until the email is sent, before sending the next one, which is not efficient.
My suggestion is sending all emails at the same time and return a promise that resolves when every email is sent. That should look something like this:
//change this
for (const email of emailsToSend) {
await send(email.address);
}
// --------------into this--------------------------------
//This is an array of promises
const promises = emailsToSend.map(email => {
return send(email.address);
});
await Promise.all(promises);
Hope that helps :)