skip to Main Content

I have a foreach loop that is, well… too fast. The device I’m trying to communicate with is confused. The device sends a response to a listener (which is somewhere else and does more than that), so it’s impossible (as far as I know) to await the response somehow. So I thought I could do smt like this:

something.forEach(async item => {
//do smt
await setTimeout(() => {
  console.log("czekamy czekamy")
}, 2000)
})

hoping that it could stop the loop for executing the next iteration. But it doesn’t work, obviously. Is there a way to achieve what I’m trying to achieve?

3

Answers


  1. You have to make the forEach loop async in order to await the timeout.

    something.forEach(async item => {
    //do smt
    await setTimeout(() => {
      console.log("czekamy czekamy")
    }, 2000)
    })
    

    Edit:
    You should return create and use a Promise that resolves the timeout:

    function delay(ms) {
      return new Promise(resolve => setTimeout(resolve, ms));
    }
    
    async function processItems() {
      await something.forEach(async item => {
        // Perform some action on each item
        console.log(item);
    
        // Wait for 2 seconds before processing the next item
        await delay(2000);
      });
    }
    
    
    Login or Signup to reply.
  2. Array.forEach() will not await for each item to complete.

    If you want to have a serial execution so the next items waits until the previous is over, you can use a for-loop:

    for (let item in something) {
      await setTimeout(...);
    }
    
    Login or Signup to reply.
  3. You should use a Promise and resolve it inside the setTimeout’s callback function. Also you can’t use forEach because it calls the callback immediately without waiting of resolving of the promise returned from the callback function:

    const something = [1,2];
    (async()=>{
      for(const item of something){
          //do smt
          await new Promise(resolve => setTimeout(() => {
              console.log(`czekamy czekamy ${item}`);
              resolve();
          }, 2000)
          );
      }
    })();

    A more generic approach would be to create a wait promise function:

    const something = [1,2];
    const wait = (delay = 0) => new Promise(resolve => setTimeout(resolve, delay));
    (async()=>{
      for(const item of something){
          //do smt
          await wait(2000);
          console.log(`czekamy czekamy ${item}`);
      }
    })();

    But I would try an async generator as the final solution:

    const something = [1,2];
    
    const wait = (delay = 0) => new Promise(resolve => setTimeout(resolve, delay));
    
    async function* delayQueue(iterable, delay = 0){
      for(const item of iterable){
        yield item;
        await wait(delay)
      }
    }
    
    (async()=>{
      for await(const item of delayQueue(something, 2000)){
          console.log(`czekamy czekamy ${item}`);
      }
    })();

    Also note that you can use await without async in the top level of JS modules:

    <script type="module">
    const something = [1,2];
    
    const wait = (delay = 0) => new Promise(resolve => setTimeout(resolve, delay));
    
    async function* delayQueue(iterable, delay = 0){
      for(const item of iterable){
        yield item;
        await wait(delay)
      }
    }
    
    for await(const item of delayQueue(something, 2000)){
        console.log(`czekamy czekamy ${item}`);
    }
    
    </script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search