Search code examples
javascriptloopstimeforeachdelay

setTimeout inside ForEach does not wait with the specific ms given


ForEach console.log's very fast. But i need it to wait every 8sec before console.log the next item in Set. I tried setTimeout but it doesn't seem to console.log at the specific ms given.

const completedIds = [];

//Dom mutation observer
const observeChat = new MutationObserver(function(mutationsList) {
  for (let mutation of mutationsList) {
    if (mutation.addedNodes.length) {


      for (i = 0; i < mutation.addedNodes.length; i++) {
mutation.addedNodes[i].firstChild.naturalWidth < 51 ? pm(mutation.addedNodes[i].firstChild.src.slice(-48, -12)) : false
      }
      
    }
  }
});
observeChat.observe(document.querySelector('.accounts-container__list'), {attributes: true, childList: true, subtree: false});

// Pm function
pm = ids => {
  observeChat.disconnect();
  if (!completedIds.includes(ids)) {
    const img = new Set().add(ids).forEach(function(id, index) {
      setTimeout(function() { // Not working. Does NOT print in console every 8sec
        console.log(id)
      }, index * 8000)
    })
  }
  observeChat.observe(document.querySelector('.accounts-container__list'), {attributes: true, childList: true, subtree: false});
}

Solution

  • There are a couple of problems here.

    1. You're creating a Set with only one entry in it. add doesn't spread out entries you give it. If you're giving it an array, you're getting a set with just that array in it. I suspect you wanted to spread it out.

    2. The "indexes" of a set are the same as its values, so index * 8000 will try to multiply the ID you just added by 8000. It's not an index like the one array's forEach gives you.

    3. img will always be undefined, because the return value of Set.prototype.forEach is undefined.

    I suspect you're using Set to get unique values. If so, you want to:

    1. Use new Set(...ids) to create the set, and

    2. Convert it back to an array before using forEach

    3. Intialize img in some other way. It's not clear to me what it's meant to be, so I can't help with that part...

    Something along these lines:

        [...new Set(ids)].forEach(function(id, index) {
    //  ^^^^−−−−−−−^^^^^^−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− here
            setTimeout(function() {
                console.log(id);
            }, index * 8000);
        });
    

    Live Example:

    const ids = ["a", "b", "c"];
    [...new Set(ids)].forEach(function(id, index) {
        setTimeout(function() {
            console.log(id, new Date());
        }, index * 8000);
    });

    Alternatively, you could use a for-of loop with a counter:

    let index = 0;
    for (const id of [...new Set(ids)]) {
        setTimeout(function() {
            console.log(id);
        }, index++ * 8000);
    }
    

    Live Example:

    let index = 0;
    for (const id of [...new Set(ids)]) {
        setTimeout(function() {
            console.log(id);
        }, index++ * 8000);
    }