1

I'm building some Node.js app and have a function like this:

function ex() {
  allowUA = false;

  for (var i = 0; i < arr.length; i++) {
    (function(index) {
      setTimeout(() => {
        console.log(index);
      }, i * 3000);
    })(i);
  }

  if (i == arr.length - 1) {
    allowUA = true;
  }
}

All I want is that function to execute in strict order (changing variable to false, doing the loop and then changing variable back to true)

I found out that it's not as easy as it seems, so I ask for your help.

Is there a way to do this? Thanks in advance.

Sushanth --
  • 55,259
  • 9
  • 66
  • 105
N. Levenets
  • 77
  • 1
  • 1
  • 8
  • 1
    One way is to get rid of `setTimeout` – Sushanth -- Nov 28 '18 at 21:12
  • 1
    Possible duplicate of [Javascript: Run async task in series(or sequence) without libraries](https://stackoverflow.com/questions/49763148/javascript-run-async-task-in-seriesor-sequence-without-libraries) – Heretic Monkey Nov 28 '18 at 21:14
  • @Sushanth-- Impossible. It's crucial here. The one above is just the example. I hope you didn't mean that's the ONLY solution possible... – N. Levenets Nov 28 '18 at 21:15
  • 2
    Think through how JavaScript runs this code. It will run the `for` loop very quickly and each `setTimeout` will run virtually simultaneously. Your variable `i` will reach the end of the loop and and the condition you set will evaluate to true milliseconds, long before the timeouts terminate. So, what is it that you want your function to do before setting this value to true? Knowing that can help us to advise you. – wlh Nov 28 '18 at 21:23

2 Answers2

1

You can use Promise to make sure that the timeout resolves first and then log the next condition when all the promises resolve.

let allowUA = false;
let arr = [1, 2, 3]

function ex() {
  allowUA = false;
  console.log('false');

  // iterate over the array and create a promise for each iteration
  let promises = arr.map(function(value, index) {
    return new Promise(function(resolve) {
      setTimeout(() => {
        console.log(index);
        // resolve the promise
        resolve();
      }, index * 500);
    });
  })

  // run this when all the promises resolve themselves
  Promise.all(promises).then(function() {
    allowUA = true;
    console.log('true');
  });
}

ex()
Sushanth --
  • 55,259
  • 9
  • 66
  • 105
0

Here's an async/await method that that forgoes a for/loop in favour of a setTimeout that calls a function with an slowly-shortening array:

async function ex(arr) {
  allowUA = false;
  console.log(allowUA);

  function logger(arr) {
    return new Promise((resolve, reject) => {
      (function loop(arr) {
        const [head, ...rest] = arr;
        if (!arr.length) {
          resolve();
        } else {
          console.log(head);
          setTimeout(() => loop(rest), head * 1000);
        }
      }(arr));
    });
  };
  
  await logger(arr);

  allowUA = true;
  console.log(allowUA);
}

const arr = [1, 2, 3, 4];
ex(arr);
Andy
  • 61,948
  • 13
  • 68
  • 95