11

I'm trying to get multiple data objects from The Movie Database at once using Promise.all. After I loop through all the results of the fetch call, and use .json() on each bit of data, I tried to log it to the console. However, rather than an array of objects with data, I'm getting an array of Promises. Nested in the promises, I can see my data, but I'm clearly missing a step in order to have an array of data objects, instead of just Promises.

What am I missing here?

 //store movie API URLs into meaningful variables
    const trending = `https://api.themoviedb.org/3/trending/all/day?api_key=${API_KEY}`;
    const topRated = `https://api.themoviedb.org/3/movie/top_rated?api_key=${API_KEY}&language=en-US&page=1`;
    const nowPlaying = `https://api.themoviedb.org/3/movie/now_playing?api_key=${API_KEY}&language=en-US&page=1`;
    const upcoming = `https://api.themoviedb.org/3/movie/upcoming?api_key=${API_KEY}&language=en-US&page=1`;
    //create an array of urls to fetch data from
    const allMovieURLs = [trending, topRated, nowPlaying, upcoming];
    const promiseURLs = allMovieURLs.map(url => fetch(url));
    Promise.all(promiseURLs)
      .then(responses => responses.map(url => url.json()))
      .then(dataArr => console.log(dataArr));
  };
WonkasWilly
  • 563
  • 1
  • 8
  • 21
  • 3
    It's not the problem, but that code makes two common mistakes that may hit you at some point. 1. You're not checking that the requests succeed. This is such a common error (in my view, an error in the `fetch` API) that I [wrote it up](http://blog.niftysnippets.org/2018/06/common-fetch-errors.html) on my anemic little blog. Check `.ok` on the responses. 2. You're not handling rejection of your `Promise.all` promise, and not passing it to something that will handle it. You need to either handle it or pass the promise on to something that will. – T.J. Crowder Feb 24 '19 at 14:31
  • closely related: [Why does .json() return a promise?](https://stackoverflow.com/q/37555031/1048572) – Bergi Feb 24 '19 at 15:19
  • 1
    @T.J.Crowder This is an awesome addition to a problem I didn't even know I was having. Much appreciated! – WonkasWilly Feb 25 '19 at 06:47

2 Answers2

19

Your .then(responses => responses.map(url => url.json())) resolves to an array of Promises, so you need to call Promise.all again if you want to wait for all to resolve:

Promise.all(promiseURLs)
  .then(responses => Promise.all(responses.map(url => url.json())))
  .then(dataArr => console.log(dataArr));

Or, you might consider using just one Promise.all, and having each URL fetch and the json, that way some items aren't idle in the middle of script execution:

const allMovieURLs = [trending, topRated, nowPlaying, upcoming];
const promiseURLs = allMovieURLs.map(url => fetch(url).then(res => res.json()));
Promise.all(promiseURLs)
  .then(dataArr => console.log(dataArr));
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • I didn't realize that `Body.json` also returned a `Promise`! Your explanation was simple and concise, and this has solved my problem. Thank you. – WonkasWilly Feb 24 '19 at 09:33
  • 1
    Probably worth pointing out the missing `.ok` check (I've done so now in a comment on the question). – T.J. Crowder Feb 24 '19 at 14:32
4

try doing it this way

const promiseURLs = allMovieURLs.map(url => fetch(url).then(res => res.json()));
Promise.all(promiseURLs)
  .then(responses => responses.forEach(response => { console.log(response)})
George.S
  • 149
  • 8