Javascript fetch() chain synchronous

The following code fetches a json list and then does another fetch call for each list item to change their value. The problem is that it’s not done synchronously. “new” is printed to the console before “update”. I’ve been scratching my head at this for hours

fetch(API_URL_DIARY)
.then(response => response.json())
.then(data => {
  console.log("old", data);
  return data;
})
.then(data => {
  data.forEach(function(e, index,array) {
    fetch(API_URL_FOOD_DETAILS + e.foodid)
    .then(response => response.json())
    .then(data => {
      array[index] = {...e, ...data};
      console.log("update");
    })
  });

  console.log("new", data)
});

You’re dealing with multiple Promises, you may want to look at Promise.all() - https://devdocs.io/javascript/global_objects/promise/all

This is a function to which you simply pass an array of Promises (in your case, fetch requests) and, when they all resolve, run a callback function.

Thanks @snowmonkey
I’ve looked into Promise.all() but I’m not sure how I can make the second fetch() depend on the first one when done that way.

You are basically going to have to do it the way you already are because it’s in sequence: the initial request has to complete prior to the second set of requests. Using Promise.all is a good idea here, but you still need to set up the call to it after the first request.

Note that async/await will make the whole thing a lot cleaner (although you’ll be doing the exact same thing), it’ll completely remove the nested callbacks and let you write one thing after another.

Edit: you’d use it something like this (this is basically pseudo code, written very quickly, not tested and I suspect it’s slightly wrong, but you should get the idea):

async function example() {
  const diaryReq = await fetch(diaryURL);
  const diaryData = await diaryReq.json();
  const foodReqs = await Promise.all(diaryData.map(({foodid}) => fetch(foodURL + foodid));
  return diaryData.map((data, i) => ({...data, ...foodData[i].json()}));
}
1 Like

Did you mean the following instead?

return diaryData.map((data, i) => ({…data, …foodReqs[i].json()}));

Also, would there need to be an await before the …foodReqs[i].json()?

Yeah, though shouldn’t need an await (the data should all be resolved at that point? and I don’t want to return promises). As I say, is basically pseudo code; it’s the order things go in but I’d need to actually write it and check it rather than just dumping down how I remembered it working

1 Like