Vladyslav Semeniuk
Vladyslav Semeniuk

Reputation: 557

Fetch in fetch inside a loop JS

The question is, how can I get rid of calling second fetch 300 times? Or is there another way to do that, what I`m doing? Additionally how to do ordered(don`t wanna sort) calls of first api, because they`re coming from api in chaotic asynchronous way?

for(let i=1;i<=300; i++) {
  fetch(`example.api/incomes/${i}`)   // should be returned 300 times
    .then(response => {
      if(response.ok) return response.json();
      throw new Error(response.statusText);
    })
    .then(function handleData(data) {
        return fetch('example.api')   // should be returned 1 time
        .then(response => {
            if(response.ok) return response.json();
            throw new Error(response.statusText);
          })
    })
    .catch(function handleError(error) {
        console.log("Error" +error);            
    }); 
};

Upvotes: 6

Views: 29508

Answers (3)

SteeveDroz
SteeveDroz

Reputation: 6136

The other answers are perfectly valid, but a bit outdated. Here is a new way of doing it with async/await:

async function repeat(uri, amount) {
    const result = []
    for (let i = 1; i <= amount; i++) {
        const response = await fetch(`${uri}/${i}`) // waits for the response
        const data = await response.json()
        result.push(...data)
    }

    return data
}

repeat('example.api/incomes', 300)
    .then(handleData) // defined elsewhere or anonymous
    .catch(handleError) // defined elsewhere or anonymous
}

If you don't know about this, async/await is basically a clearer way to write promises.

The async function declaration creates a binding of a new async function to a given name. The await keyword is permitted within the function body, enabling asynchronous, promise-based behavior to be written in a cleaner style and avoiding the need to explicitly configure promise chains.

(Source)

Upvotes: 2

Emiel Zuurbier
Emiel Zuurbier

Reputation: 20934

Store all of your requests in an array. Then use Promise.all() the wait for all of those requests to finish. Then when all of the requests are finished, use another Promise.all() with a map() inside of it to return the the JSON of each request and wait for all of those to finish.

Now your data argument will have an array of objects available in the next then callback.

function fetch300Times() {
  let responses = [];
  for(let i = 1; i <= 300; i++) {.
    let response = fetch(`example.api/incomes/${i}`);
    responses.push(response);
  } 
  return Promise.all(responses);
}

const awaitJson = (response) => Promise.all(responses.map(response => {
  if(response.ok) return response.json();
  throw new Error(response.statusText);
}));

fetch300Times()
  .then(awaitJson)
  .then(data => {
    fetch('example.api')   // should be returned 1 time
      .then(response => {
        if(response.ok) return response.json();
        throw new Error(response.statusText);
      });
  }).catch(function handleError(error) {
    console.log("Error" +error);            
  });  

Upvotes: 0

xdeepakv
xdeepakv

Reputation: 8125

You can solve it using Promise all.

let promises = [];
for (let i = 1; i <= 300; i++) {
  promises.push(fetch(`example.api/incomes/${i}`));
}
Promise.all(promises)
  .then(function handleData(data) {
    return fetch("example.api") // should be returned 1 time
      .then(response => {
        if (response.ok) return response.json();
        throw new Error(response.statusText);
      });
  })
  .catch(function handleError(error) {
    console.log("Error" + error);
  });

Upvotes: 17

Related Questions