0

I have the following structure of code:

var cdict = new Map();

fetch("randomurl")
.then(res => res.json())
.then(data => {

    for (const obj of data.result) {
        // insert stuff into Map cdict
    }
    counter(0).then(res => {
        console.log(cdict);
    }) 
  
  // ^ here after calling of counter i need to do stuff

});


const cbegin = 0;
const ccount = 10;

function counter(cnt) {
    if (cnt < ccount) {
        setTimeout( () => {
            cnt++;
            
            fetch(someurl)
            .then(res => res.json())
            .then(data => {

                for (const obj of data.result) {
                    // do stuff
                }
                
            })
            .catch(err => {
                console.log(err);
            });

            counter(cnt);
        }, 1000);
    }
}


Here after execution of counter(0) call and all its fetch requests, I wish to execute a line console.log(cdict);

How can this be achieved? And is this proper way to call fetch requests with delay of 1 second?

jeea
  • 151
  • 7
  • You'll likely need to look at returning a promise which yields after the delay – Hive7 May 15 '21 at 11:15
  • 1
    [What is the JavaScript version of sleep()?](https://stackoverflow.com/questions/951021/what-is-the-javascript-version-of-sleep) – Andreas May 15 '21 at 11:18

1 Answers1

2

Don't mix setTimeout event queue callbacks with promise-based code -

const sleep = time =>
  new Promise(resolve => setTimeout(resolve, time))

async function main()
{ console.log("please wait 5 seconds...")
  await sleep(5000)
  console.log("thanks for waiting")
  return "done"
}

main().then(console.log, console.error)

Don't write .then(res => res.json()) every time you need some JSON. Write it once and reuse it -

const fetchJSON(url, options = {}) =>
  fetch(url, options).then(res => res.json())

async function main()
{ const data = await fetchJSON("path/to/data.json")
  console.log("data received", data)
  return ...
}

main().then(console.log, console.error)

Don't attempt to declare variables outside of Promises and modify them later. You cannot return the result of an asynchronous call. Asynchronous data needs to stay contained within the promise or you will be chasing hard-to-find bugs in your code -

async function main(urls)
{ const result = []
  for (const u of urls)           // for each url,
  { result.push(await getJSON(u)) // await fetch and append to result
    sleep(1000)                   // wait 1 second
  }
  return result
}

const myUrls =
  [ "foo/path/data.json"
  , "another/something.json"
  , "and/more/here.json"
  ]

main(urls)
  .then(result => /* counter logic */)
  .then(console.log, console.error)

Continue abstracting as you see fit -

// give reusable functions a name; use parameters for configurable behaviour
async function fetchAll(urls, delay = 100)
{ const result = []
  for (const u of urls)
  { result.push(await getJSON(u))
    sleep(delay)
  }
  return result
}

async function counter(urls)
{ const results = await fetchAll(urls) // use our generic fetchAll
  const cdict = /* counter logic... */
  return cdict
}

const myUrls =
  [ "foo/path/data.json"
  , "another/something.json"
  , "and/more/here.json"
  ]

counter(urls).then(console.log, console.error)

As you can see async and await prevent nesting that occurs with the use of setTimeout or .then callbacks. If you use them correctly, your code remains flat and you can think about your code in a synchronous way.

Mulan
  • 129,518
  • 31
  • 228
  • 259