This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
I want to push data from promise to array (coursesArray) and then use the array values else where. I am using node-fetch library to query the API. Currently when i log array inside the promise, it has values(coursesOne) however when i log the array outside the promise, it is empty(coursesTwo). How do i go about implementing the ideal solution so that coursesArray is filled with data when getCoursesForSitemap() executes
Here is what i have implemented so far
const coursesArray = [];
const getCoursesForSitemap = () => {
fetch(coursesUrl)
.then(res => res.json())
.then(json => {
json.courses.results.map(course => {
return coursesArray.push(course.slug);
});
console.log('coursesOne', coursesArray);
})
.catch(error => {
console.log(error);
});
};
getCoursesForSitemap();
console.log('coursesTwo', coursesArray);
Refactoring your code to use async/await, and not making it mutate the out-of-closure/global variable, this should work for you.
const getCoursesForSitemap = async () => {
const result = await fetch(coursesUrl);
const json = await result.json();
return json.courses.results.map(course => course.slug);
};
const coursesArray = await getCoursesForSitemap();
console.log('coursesTwo', coursesArray);
In case your environment doesn't support top-level async/await, you'll need to execute the async code in e.g. an IIFE:
(async function() {
const coursesArray = await getCoursesForSitemap();
console.log('coursesTwo', coursesArray);
}());
(That function will also return a promise you can .then() or await on...)
You are trying to log the values before they are resolved from your promise. That's why it's not working. You need to wait for the Promise to be resolve before trying to show them.
You also need to return the promise .
const coursesArray = [];
const getCoursesForSitemap = () => {
return fetch(coursesUrl)
.then(res => res.json())
.then(json => {
json.courses.results.forEach(course => {
return coursesArray.push(course.slug);
});
console.log('coursesOne', coursesArray);
})
.catch(error => {
console.log(error);
});
};
getCoursesForSitemap().then(() => {
console.log('coursesTwo', coursesArray);
});
I've also changed the map function you use for a forEach since you don't need to change the value of the json.courses.results array.
Related
I'm facing a probably super easy to solve problem regarding fetching.
I'd like to fetch some json datas and store it in a variable to access it later.
The problem is that I always ends up getting undefined in my variable. What's the way to do to deal with that kind of data storing ?
Here's my code.
const fetchCities = () => {
fetch('cities.json')
.then(response => response.json())
.then(data => {
return data;
});
}
let cities = fetchCities();
console.log(cities)
Already looked up for answers but couldn't find a way to do. Thanks !
You could do this very simply with async/await like this:
const fetchCities = async () => {
let cities = await fetch('cities.json');
return cities.json();
};
let cities = await fetchCities();
console.log(cities);
Sending a fetch request takes time, so the console.log works before the data arrives.
The best way to deal with fetch is using async functions and await like so:
const fetchCities = ()=>{
return fetch('cities.json');
}
async function main(){
try {
const res = await fetchCities();
const data = await res.json();
// handle the data here, this will work only after the data arrival
console.log(data);
} catch (err) {
console.log(err);
}
}
main();
Note: await can only be used in async functions, that's the main purpose of the main function.
Or if you want to use .then:
const fetchCities = ()=>{
return fetch('cities.json');
}
function main(){
fetchCities()
.then(res => res.json())
.then(data => {
// handle the data here, all you code should be here
})
.catch (err => console.log(err));
}
main();
I've trying to retrieve the data, but I can't return it, can only see it in the console,
it's a simple axios get function but for some reason, I keep getting Promise even after using async/await.
my goal is to save the data to the memory.
any help would really be appreciated
let fetchTodo = async () => {
await axios.get('https://jsonplaceholder.typicode.com/todos/1')
.then(res => console.log(res.data))
.then(res => { return res })
.catch(err => console.log(err))
};
console.log("TEST: ", fetchTodo())
console
Asycn function always returns a promise, to get data from the fetchTodo function you need to create another async function which will await the result returned by fetchTodo(). if you are using react, you can use states and update the state while you are inside the .then chain of the fetchTodo function.
Asycn function always returns a promise. For getting or saving data you need to get it from .then() function. Here you can check the example. Hope so it will help you.
let fetchTodo = async () => {
await axios.get('https://jsonplaceholder.typicode.com/todos/1')
.then(res => console.log(res.data))
.then(res => {
// here you can performance your task, save data, send
// response or anything else
return res
})
.catch(err => console.log(err))
};
fetchTodo()
The async/await syntax means a function will return a Promise.
If you want to return the value, you could do something like this:
let fetchTodo = async () => {
try {
const res = await axios.get("https://jsonplaceholder.typicode.com/todos/1");
return res;
} catch (error) {
console.log(error);
}
};
// For the folowing code to work, it must be placed inside a async function as well
const res = await fetchTodo();
console.log(`Test: ${res.data}`);
// If it's a Top level call, use the folowing code
const res = fetchTodo().then( res => {
const data = res.data;
// The rest of your code goes here.
// ...
// ...
// ...
}).catch( error => {
console.log(error);
});
Some more information about it on: How can I use async/await at the top level?
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 2 years ago.
That my Code trying to returning response.data.
const getRobots = () => {
axios.get("https://jsonplaceholder.typicode.com/users").then((response) => {
return response.data;
});
};
let robotsValue = getRobots();
console.log(robotsValue);
Pending
You need to use the then after you call the function, not inside it. I changed it to fetch so i could show you in a snippet.
const getRobotsThen = () => {
return fetch("https://jsonplaceholder.typicode.com/users");
};
getRobotsThen()
.then(res => res.json())
.then(data => console.log(data));
Another option is to use the async await combo
const getRobotsAsync = async () => {
const res = await fetch("https://jsonplaceholder.typicode.com/users");
return await res.json();
}
// await only works in an async function, thats why there is an IIFE
(async () => {
let robotsValueAsync = await getRobotsAsync();
console.log(robotsValueAsync);
})()
I have a service to get a list from server. But in this list I need to call another service to return the logo img, the service return ok, but my list remains empty. What i'm did wrong ?
I tried to use async/await in both services
I tried to use a separate function to get the logos later, but my html don't change.
async getOpportunitiesByPage(_searchQueryAdvanced: any = 'active:true') {
this.listaOportunidades = await this._opportunities
.listaOportunidades(this.pageSize, this.currentPage, _searchQueryAdvanced)
.toPromise()
.then(result => {
this.totalSize = result['totalElements'];
return result['content'].map(async (opportunities: any) => {
opportunities.logoDesktopUrl = await this.getBrand(opportunities['brandsUuid']);
console.log(opportunities.logoDesktopUrl);
return { opportunities };
});
});
this.getTasks(this.totalSize);
}
No errors, just my html don't change.
in my
console.log(opportunities.logoDesktopUrl);
return undefined
but in the end return filled.
info:
Angular 7
server amazon aws.
await is used to wait for promise.
You should return promise from getBrand if you want to wait for it in getOpportunitiesByPage.
Change the getBrand function as following.
getBrand(brandsUuid): Observable<string> {
this.brandService.getById(brandsUuid).pipe(map(res => {
console.log(res.logoDesktopUrl); return res.logoDesktopUrl;
}))
}
Change opportunities.logoDesktopUrl = await this.getBrand(opportunities['brandsUuid']); to opportunities.logoDesktopUrl = await this.getBrand(opportunities['brandsUuid']).toPromise();
Please make sure you imported map from rxjs/operators.
At first,when you await, you should not use then.
At second, async/await runs only with Promises.
async getOpportunitiesByPage(_searchQueryAdvanced: any = 'active:true') {
const result = await this._opportunities
.listaOportunidades(this.pageSize, this.currentPage, _searchQueryAdvanced)
.toPromise();
this.totalSize = result['totalElements'];
this.listaOportunidades = result['content'].map(async (opportunities: any) => {
opportunities.logoDesktopUrl = await this.getBrand(opportunities['brandsUuid']);
console.log(opportunities.logoDesktopUrl);
return opportunities;
});
this.getTasks(this.totalSize);
}
getBrand(brandsUuid) {
return new Promise((resolve, reject) => {
this.brandService.getById(brandsUuid).subscribe(res => {
console.log(res.logoDesktopUrl);
return resolve(res.logoDesktopUrl);
}, err => {
return reject(err);
});
});
}
But, because rxjs is a used in Angular, you should use it instead of async/await :
getOpportunitiesByPage: void(_searchQueryAdanced: any = 'active:true') {
this._opportunities.listaOportunidades(this.pageSize, this.currentPage, _searchQueryAdvanced).pipe(
tap(result => {
// we do that here because the original result will be "lost" after the next 'flatMap' operation
this.totalSize = result['totalElements'];
}),
// first, we create an array of observables then flatten it with flatMap
flatMap(result => result['content'].map(opportunities => this.getBrand(opportunities['brandsUuid']).pipe(
// merge logoDesktopUrl into opportunities object
map(logoDesktopUrl => ({...opportunities, ...{logoDesktopUrl}}))
)
),
// then we make each observable of flattened array complete
mergeAll(),
// then we wait for each observable to complete and push each result in an array
toArray()
).subscribe(
opportunitiesWithLogoUrl => {
this.listaOportunidades = opportunitiesWithLogoUrl;
this.getTasks(this.totalSize);
}, err => console.log(err)
);
}
getBrand(brandsUuid): Observable<string> {
return this.brandService.getById(brandsUuid).pipe(
map(res => res.logoDesktopUrl)
);
}
Here is a working example on stackblittz
There might be a simpler way to do it but it runs :-)
This question already exists:
Transform forEach in Promise (without ASYC/AWAIT) [duplicate]
Closed 3 years ago.
I need to transform a forEach in promise. The code is legacy and I can't use async/await operators.
Promise.all(Object.entries(data).forEach(function (data) {
let [data1, data2] = data
let info;
consultData.getResponse(data1).then(result => info = result).then(function () {
return dataServices.find(info)
.then(function (result) {
// do things
})
.then(function (info) {
// do final things
})
})
})).then((result) => {
// do something when all things have intereted and finished
})
But output that Promise.all can't be used. If I try with Promise.resolve, the last is printed before all things have finished their processing.
How I can transform the forEach in a promise for i can use .then() after all iteration?
ASYNC/AWAIT DON'T WORK IN THIS CODE
As #Jonas Wilms indicated, you can use .map returning each promise and after that you can use Promise.all
const entries = Object.entries(data);
const arrayOfPromises = entries.map((item) => {
return new Promise((resolve, reject) => {
const [data1, data2] = item;
consultData.getResponse(data1).then((result) => {
return dataServices.find(info);
}).then((infoServiceResult) => {
return resolve(infoServiceResult);
}).catch((err) => {
return reject(err);
});
});
});
Promise.all(arrayOfPromises).then((data) => {
// data is an array of each infoServiceResult
console.log(data);
}).catch((err) => {
console.error(err);
});