[Learning/Beginner] Confused about await, async and fetch.
-
Still learning. I'm using the [SWAPI - The Star Wars API](https://swapi.dev/) for my test data. I can fetch the data from [https://swapi.dev/api/people\](https://swapi.dev/api/people) (no problem) But I'd like to be able to iterate over the films array to fetch each movie name. I'm not sure what the syntax I should use, or if it is the proper way to do it. the getFilmName function returns
[object Promise]
I tried adding an await before the call to getFilmName and give does not "compile" :
const filmName = **await** getFilmName(filmURL);
Thanks.
async function getFilmName(url) {
const res = await fetch(url);
const data = await res.json();
return data.title;
}async function getPeople() {
console.log("fetchNames");
// get list of people.
const url = "https://swapi.dev/api/people";
const res = await fetch(url);
const data = await res.json();console.log(data);
const results = data.results;
// loop all people
results.map((person) => {
console.log(`${person.name} stars in : `);
// loop all films for each person
person.films.map((filmURL) => {
console.log(filmURL);
const filmName = getFilmName(filmURL);
console.log(`filmName: ${filmName}`);
});
});
}getPeople();
Thanks.
CI/CD = Continuous Impediment/Continuous Despair
-
Still learning. I'm using the [SWAPI - The Star Wars API](https://swapi.dev/) for my test data. I can fetch the data from [https://swapi.dev/api/people\](https://swapi.dev/api/people) (no problem) But I'd like to be able to iterate over the films array to fetch each movie name. I'm not sure what the syntax I should use, or if it is the proper way to do it. the getFilmName function returns
[object Promise]
I tried adding an await before the call to getFilmName and give does not "compile" :
const filmName = **await** getFilmName(filmURL);
Thanks.
async function getFilmName(url) {
const res = await fetch(url);
const data = await res.json();
return data.title;
}async function getPeople() {
console.log("fetchNames");
// get list of people.
const url = "https://swapi.dev/api/people";
const res = await fetch(url);
const data = await res.json();console.log(data);
const results = data.results;
// loop all people
results.map((person) => {
console.log(`${person.name} stars in : `);
// loop all films for each person
person.films.map((filmURL) => {
console.log(filmURL);
const filmName = getFilmName(filmURL);
console.log(`filmName: ${filmName}`);
});
});
}getPeople();
Thanks.
CI/CD = Continuous Impediment/Continuous Despair
Maximilien wrote:
I tried adding an await before the call to getFilmName and give does not "compile" :
The calling function would also have to be asynchronous or called within the context of a promise.
async function blah() {
try {
// protocol in URL removed because of syntax coloring bug
const response = await fetch('blah.com');
return await response.json();
} catch(ex) {
console.error(ex);
}
}// if you call blah synchronously, it will not work
blah(); // problem// call it from another async routine, thenable promise, or an async IIFE
(async () => {
await blah(); // works
})();Jeremy Falcon
-
Maximilien wrote:
I tried adding an await before the call to getFilmName and give does not "compile" :
The calling function would also have to be asynchronous or called within the context of a promise.
async function blah() {
try {
// protocol in URL removed because of syntax coloring bug
const response = await fetch('blah.com');
return await response.json();
} catch(ex) {
console.error(ex);
}
}// if you call blah synchronously, it will not work
blah(); // problem// call it from another async routine, thenable promise, or an async IIFE
(async () => {
await blah(); // works
})();Jeremy Falcon
Thanks, but that does not help with my example. My problem is with the getFilmName function (or the call to).
CI/CD = Continuous Impediment/Continuous Despair
-
Still learning. I'm using the [SWAPI - The Star Wars API](https://swapi.dev/) for my test data. I can fetch the data from [https://swapi.dev/api/people\](https://swapi.dev/api/people) (no problem) But I'd like to be able to iterate over the films array to fetch each movie name. I'm not sure what the syntax I should use, or if it is the proper way to do it. the getFilmName function returns
[object Promise]
I tried adding an await before the call to getFilmName and give does not "compile" :
const filmName = **await** getFilmName(filmURL);
Thanks.
async function getFilmName(url) {
const res = await fetch(url);
const data = await res.json();
return data.title;
}async function getPeople() {
console.log("fetchNames");
// get list of people.
const url = "https://swapi.dev/api/people";
const res = await fetch(url);
const data = await res.json();console.log(data);
const results = data.results;
// loop all people
results.map((person) => {
console.log(`${person.name} stars in : `);
// loop all films for each person
person.films.map((filmURL) => {
console.log(filmURL);
const filmName = getFilmName(filmURL);
console.log(`filmName: ${filmName}`);
});
});
}getPeople();
Thanks.
CI/CD = Continuous Impediment/Continuous Despair
If you look at the output from https://swapi.dev/api/films[^], it is in exactly the same format as the output from https://swapi.dev/api/people[^]. So you should be able to use the same method for both types. The only difference is the URI that you pass in to the method.
-
Still learning. I'm using the [SWAPI - The Star Wars API](https://swapi.dev/) for my test data. I can fetch the data from [https://swapi.dev/api/people\](https://swapi.dev/api/people) (no problem) But I'd like to be able to iterate over the films array to fetch each movie name. I'm not sure what the syntax I should use, or if it is the proper way to do it. the getFilmName function returns
[object Promise]
I tried adding an await before the call to getFilmName and give does not "compile" :
const filmName = **await** getFilmName(filmURL);
Thanks.
async function getFilmName(url) {
const res = await fetch(url);
const data = await res.json();
return data.title;
}async function getPeople() {
console.log("fetchNames");
// get list of people.
const url = "https://swapi.dev/api/people";
const res = await fetch(url);
const data = await res.json();console.log(data);
const results = data.results;
// loop all people
results.map((person) => {
console.log(`${person.name} stars in : `);
// loop all films for each person
person.films.map((filmURL) => {
console.log(filmURL);
const filmName = getFilmName(filmURL);
console.log(`filmName: ${filmName}`);
});
});
}getPeople();
Thanks.
CI/CD = Continuous Impediment/Continuous Despair
Jeremy is correct - any function that uses
await
needs to be marked asasync
. In this case, the callback tomap
would need to beasync
. However, that would result in an array of promises. But since you're not doing anything with the array returned from eithermap
call, that won't make much difference. Assuming you actually want to do something with the results, try:async function getPeople() {
console.log("fetchNames");
const url = "https://swapi.dev/api/people";
const res = await fetch(url);
const data = await res.json();
console.log(data);const results = data.results; const promises = results.map(async (person) => { const filmPromises = person.films.map(getFilmName); const films = await Promise.all(filmPromises); return { person, films }; }); return await Promise.all(promises);
}
(async () => {
const people = await getPeople();
people.forEach(person => {
console.log(`${person.person.name} stars in :`);
person.films.forEach(filmName => console.log(filmName));
});
})();Demo[^] Promise.all() - JavaScript | MDN[^]
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
Jeremy is correct - any function that uses
await
needs to be marked asasync
. In this case, the callback tomap
would need to beasync
. However, that would result in an array of promises. But since you're not doing anything with the array returned from eithermap
call, that won't make much difference. Assuming you actually want to do something with the results, try:async function getPeople() {
console.log("fetchNames");
const url = "https://swapi.dev/api/people";
const res = await fetch(url);
const data = await res.json();
console.log(data);const results = data.results; const promises = results.map(async (person) => { const filmPromises = person.films.map(getFilmName); const films = await Promise.all(filmPromises); return { person, films }; }); return await Promise.all(promises);
}
(async () => {
const people = await getPeople();
people.forEach(person => {
console.log(`${person.person.name} stars in :`);
person.films.forEach(filmName => console.log(filmName));
});
})();Demo[^] Promise.all() - JavaScript | MDN[^]
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
Thanks, I'll study this. I'm not sure I still understand. :rose:
CI/CD = Continuous Impediment/Continuous Despair
-
Thanks, I'll study this. I'm not sure I still understand. :rose:
CI/CD = Continuous Impediment/Continuous Despair
I'll help you with the array of promises part, but not until I get a thumbs up too. :laugh:
Jeremy Falcon
-
I'll help you with the array of promises part, but not until I get a thumbs up too. :laugh:
Jeremy Falcon
I promise I will.:thumbsup:
CI/CD = Continuous Impediment/Continuous Despair
-
I promise I will.:thumbsup:
CI/CD = Continuous Impediment/Continuous Despair
Richard is spot on with his reply. Mine was more theory. Take it as a compliment. Sometimes I just chat theory when I recognize the poster because I trust they take it and run with it. It's still the same principle, but just needs to be called from within the context of an Array.prototype.map callback. There are a couple ways to go about this. 1 You can still use an async IIFE anyway. IIFE is a functional/JavaScript concept that stands for Immediately-Invoked Function Expression and is pronounced
iffy
. It does exactly what it says and can be put anywhere. It's a quick and dirty way to call async code from a sync routine as well. 2 You can make the map callback itself async. However, this means you'd also have to deal with sync/async issue still.... just "one level" higher so to speak. Array.prototype.map iterates, much like IEnumerable in C#. In JavaScript, async/await is essentially syntax sugar for promises. Makes life easier and for cleaner code. But it also means you can interchange them and loop through your nested map like this:// this level needs a promise.all too
results.map(async person => {
// loop all films for each person
await Promise.all(arr.map(async filmURL => {
const filmName = await getFilmName(filmURL);
}));
};Keep in mind though, this simply shifts the requirement for async up one nested level. The parent map would still have to be called within the context of a promise or async/await still. Same exact syntax. Keep in mind though, using Promise.all is old. It works, but no cool points for using it. As a side note, this is mainly for educational purposes. An API shouldn't be called in a loop. Redesigning the API, using GraphQL, streaming the data, etc. should all be considerations to rethink the approach of opening web requests in a loop. Buttttt.... if you need a loop-like concept, you'd be better off with generators. For example, if you used generators, you'd be able to pull off something like this. Just trying to whet your appetite. :)
for await (const filmName of getFilmNames()) {
// so fancy and clean
}Anywho, the super short answer is just go with #2 and don't forget to use promise.all on the outer nest too. :laugh:
Jeremy Falcon