typescriptpromisefetchnominatim

how to run map function (async, fetch, promise) every second one after another and not parallel?


I have a map function here, which is supposed to fetch data from an online source. The Problem is, that the API does only allow to fetch once per second. so I tried to do that like this:

const sleep = (ms: number) => {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
};

const promises = projectData.map(async (project, index) => {
        return await getAddress(asdf)
          .then((nominatimData) => {
        // ....do something...
          })
          .catch(async (e) => {
            console.log("failed", e);
            return await sleep(2000).then(() => {
              console.log("another try... ")
              return getAddress(asdf);
            });
          });
    });

    await Promise.allSettled(promises);

    console.log("Project Data", projectData); //does still fire before all getAddress() are present.. :(

there are two problems I cannot figure out:

  1. map() seems to do its job parallel (is that true?) which is kind of not what I want here - because like I said I need it to work preferably one by one every second

  2. my sleep function does not seem to work at all. the console log is just a mess and everything at once

what would be the correct way to make this work once a second? and is the fallback (just running "getAddress) again ok like that?

thank you so much!


Solution

  • To answer your question:

    1. Yes, map does not wait for the Promise to finish to proceed to the next operation, but you can fix this using a for loop.
    2. Because you run the operations with map, your sleep function runs for every item in the array at once in parallel, the logic is good, not the method

    You could use the for loop that allows async/await operations, although, since your goal is to wait for a response from the server I would recommend a custom cursor loop instead

    let cursor = 0;
    const timeout = 1000;
    const sleep = (ms) => {
        return new Promise((resolve) => {
            setTimeout(resolve, ms);
        });
    };
    
    const loop = async () => {
        // Break if index is out of bounds
        if (!projectData[cursor]) {
            return console.log('Done');
        }
    
        await getAddress(projectData[cursor]).then((nominatimData) => {
            // ....do something...
            // Proceed to the next element in the array
            cursor++;
            await loop();
    
        }).catch(async (e) => {
            console.log(`Failed, retrying in ${ timeout }ms`);
            await sleep(timeout);
            await loop(); // Retry the loop with the same cursor index
        });
    };
    await loop();