Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. Web Development
  3. JavaScript
  4. [Learning/Beginner] Confused about await, async and fetch.

[Learning/Beginner] Confused about await, async and fetch.

Scheduled Pinned Locked Moved JavaScript
jsonlearningdevopsdata-structureshelp
9 Posts 4 Posters 24 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    Maximilien
    wrote on last edited by
    #1

    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

    J L Richard DeemingR 3 Replies Last reply
    0
    • M Maximilien

      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

      J Offline
      J Offline
      Jeremy Falcon
      wrote on last edited by
      #2

      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

      M 1 Reply Last reply
      0
      • J 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

        M Offline
        M Offline
        Maximilien
        wrote on last edited by
        #3

        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

        1 Reply Last reply
        0
        • M Maximilien

          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

          L Offline
          L Offline
          Lost User
          wrote on last edited by
          #4

          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.

          1 Reply Last reply
          0
          • M Maximilien

            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

            Richard DeemingR Offline
            Richard DeemingR Offline
            Richard Deeming
            wrote on last edited by
            #5

            Jeremy is correct - any function that uses await needs to be marked as async. In this case, the callback to map would need to be async. However, that would result in an array of promises. But since you're not doing anything with the array returned from either map 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

            "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

            M 1 Reply Last reply
            0
            • Richard DeemingR Richard Deeming

              Jeremy is correct - any function that uses await needs to be marked as async. In this case, the callback to map would need to be async. However, that would result in an array of promises. But since you're not doing anything with the array returned from either map 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

              M Offline
              M Offline
              Maximilien
              wrote on last edited by
              #6

              Thanks, I'll study this. I'm not sure I still understand. :rose:

              CI/CD = Continuous Impediment/Continuous Despair

              J 1 Reply Last reply
              0
              • M Maximilien

                Thanks, I'll study this. I'm not sure I still understand. :rose:

                CI/CD = Continuous Impediment/Continuous Despair

                J Offline
                J Offline
                Jeremy Falcon
                wrote on last edited by
                #7

                I'll help you with the array of promises part, but not until I get a thumbs up too. :laugh:

                Jeremy Falcon

                M 1 Reply Last reply
                0
                • J Jeremy Falcon

                  I'll help you with the array of promises part, but not until I get a thumbs up too. :laugh:

                  Jeremy Falcon

                  M Offline
                  M Offline
                  Maximilien
                  wrote on last edited by
                  #8

                  I promise I will.:thumbsup:

                  CI/CD = Continuous Impediment/Continuous Despair

                  J 1 Reply Last reply
                  0
                  • M Maximilien

                    I promise I will.:thumbsup:

                    CI/CD = Continuous Impediment/Continuous Despair

                    J Offline
                    J Offline
                    Jeremy Falcon
                    wrote on last edited by
                    #9

                    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

                    1 Reply Last reply
                    0
                    Reply
                    • Reply as topic
                    Log in to reply
                    • Oldest to Newest
                    • Newest to Oldest
                    • Most Votes


                    • Login

                    • Don't have an account? Register

                    • Login or register to search.
                    • First post
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • World
                    • Users
                    • Groups