Javascript run loop for specified time
Asked Answered
W

3

14

I have a function that interfaces with a telephony program and calls people. I want to know, is there a method that I can use to call folks for a certain amount of time?

I'd like to run a loop like this:

    while (flag = 0) {
        call(people);

        if (<ten minutes have passed>) {
            flag = 1;
        }
    }

Any help would be appreciated.

Wilkison answered 19/2, 2013 at 21:58 Comment(3)
This seems like a very dangerous way to perform this task (in terms of performance at least). It might be better to approach it from an event standpoint: ie, if a person is added to people, then make the call.Significance
That makes a lot of sense. Still, I want an interval on which all of this will execute, could I maybe get the current time, then subtract until a sufficiently large time is reached?Wilkison
setInterval() performs an action repeatedly after a certain amount of time. So if you'd like call(people) to be called every 10 seconds, you could do that. That way a queue could be built up in people, then executed at intervals.Significance
S
15

You probably want the setTimeout() function.

Something like this should work (untested):

var keepCalling = true;

setTimeout(function () {
  keepCalling = false;
}, 60000);

while (keepCalling) {
  // callPeople();
}
body {
  height: 100vh;
  margin: 0;
}

body:hover {
  background: yellow;
}

An alternative method if you're having problems with setTimeout():

var startTime = Date.now();

while ((Date.now() - startTime) < 60000) {
  // callPeople();
}
body {
  height: 100vh;
  margin: 0;
}

body:hover {
  background: yellow;
}
Sestina answered 19/2, 2013 at 22:1 Comment(7)
Not a telemarketer or anything. Anyway, I know about setTimeout, but it doesn't work if there is other code executing: setTimeout(stop(), interval); while(notstop){} won't work, because the while loop's execution will keep setTimeout() from ever workingWilkison
I see. If you can't get the above to work, I'd probably grab the current time outside your loop and then subtract it from the current time inside the loop: If the result in milliseconds is > 60000, you've gone over 10 minutes and should exit the loop.Sestina
That's exactly what I'd like to do! ThanksWilkison
I edited my answer to show how you'd carry out the alternative approach.Sestina
You'll want to switch the > 60000 to < 60000 fyiWilkison
First example does not work, setTimeout is async and the while is synchronous. In order for it to work, the checks must be done asynchronously as well.Cheryllches
This is totally incorrect and untested. The loop will never end and the setTimeout's callback will never be executed. Also, the page will become unresponsive.Gynaecocracy
G
1

The accepted answer is incorrect and will just block the page/tab, either permanently or for a specific amount of time (assuming the browser doesn't kill it or freeze).

Based on your original code, you could calculate for how long the loop has been running on each iteration and use that in its condition:

const msToRun = 2000 // 2 seconds

// const msToRun = 600000 // 10 minutes

const t0 = performance.now() // or Date.now()

let flag = false;

let callsPerformed = 0

while (!flag) {
    ++callsPerformed;

    if (performance.now() - t0 >= msToRun) {
        flag = true;
    }
}

console.log(`${ callsPerformed } calls made.`)

However, that's probably a bad idea because JavaScript's runtime is single-threaded and based on an event loop that runs to completion, meaning each item in the event loop's queue needs to be completed before the next one can be processed (the loop as a whole, rather than the individual iterations, is a single item in that queue).

From MDN:

Each message is processed completely before any other message is processed.

This offers some nice properties when reasoning about your program, including the fact that whenever a function runs, it cannot be preempted and will run entirely before any other code runs (and can modify data the function manipulates). This differs from C, for instance, where if a function runs in a thread, it may be stopped at any point by the runtime system to run some other code in another thread.

A downside of this model is that if a message takes too long to complete, the web application is unable to process user interactions like click or scroll. The browser mitigates this with the "a script is taking too long to run" dialog. A good practice to follow is to make message processing short and if possible cut down one message into several messages.

This means that in the example above (as well as ChrisC's and yusufaytas' answers), the while loops block the event loop, preventing any other operation queued to be executed (making the page unresponsive).

This is also one of the reasons why setTimeout's delay is not guaranteed (they might actually take longer).

This series of posts might be a better start to understand that than the MDN documentation IMO: ✨♻️ JavaScript Visualized: Event Loop

⏳ Run loop for a fixed amount of time:

If what you want is to run the loop for a certain amount of time, you can do that in both a sync (blocking) and async (non-blocking) way.

You'll notice some differences in both responsiveness of the page while the loop is running as well as how many iterations you are able to run within a specific timeframe.

🛑 Run loop for a fixed amount of time - Blocking (same as the example above):

const msToRun = 2000 // 2 seconds

const t0 = performance.now() // or Date.now()

let iterations = 0

setTimeout(() => {
  console.log(`This won't be logged until the loop is over.`)
}, 0)

while ((performance.now() - t0) < msToRun) {
    ++iterations
}

console.log(`Loop run for ${ iterations } iterations.`)
body {
  height: 100vh;
  margin: 0;
}

body:hover {
  background: yellow;
}

🚦 Run "loop" for a fixed amount of time - Non-blocking (setInterval):

const msToRun = 2000 // 2 seconds

const t0 = performance.now() // or Date.now()

let iterations = 0

setTimeout(() => {
  console.log(`This will be logged before the loop is over.`)
}, 0)

const intervalID = setInterval(() => {
  ++iterations
  
  if (performance.now() - t0 >= msToRun) {
    clearInterval(intervalID)
    
    console.log(`Loop run for ${ iterations } iterations.`)
  }
})
body {
  height: 100vh;
  margin: 0;
}

body:hover {
  background: yellow;
}

🚥 Run "loop" for a fixed amount of time - Non-blocking (setTimeout):

const msToRun = 2000 // 2 seconds

const t0 = performance.now() // or Date.now()

let iterations = 0

setTimeout(() => {
  console.log(`This will be logged before the loop is over.`)
}, 0)

function runIteration() { 
  ++iterations
  
  if (performance.now() - t0 < msToRun) setTimeout(runIteration)
  else console.log(`Loop run for ${ iterations } iterations.`)
}

runIteration()
body {
  height: 100vh;
  margin: 0;
}

body:hover {
  background: yellow;
}
Gynaecocracy answered 13/8, 2023 at 18:50 Comment(0)
C
-1

You should write something like as follows:

const people = [{
  name: 'A',
  number: '32323'
}];

function call(person) {
  // Your code to start a call goes here
  console.log(`Calling person ${person.name}`);
}

async function makeCallLoop(callDuration) {
  const endTime = Date.now() + callDuration;

  while (Date.now() < endTime) {
    for (let person of people) {
      call(person);
    }

    // Sleep for one minute (adjust as needed)
    await sleep(60 * 1000); // Sleep for 1 minute
  }

  console.log("Ending call after 10 minutes.");
}

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function main() {
  const callDuration = 10 * 60 * 1000; // 10 minutes in milliseconds
  await makeCallLoop(callDuration);
}

main();
body {
  height: 100vh;
  margin: 0;
}

body:hover {
  background: yellow;
}
Calorimeter answered 19/2, 2013 at 22:3 Comment(4)
Try flag == 0, rather than flag = 0Sestina
Also, with setTimeout() inside the loop, you're going to be generating that timeout every time it loops around. Might want to move that and the flag variable outside the while.Significance
Won't that reset the timeout every iteration of the loop? Also, won't that stop the loop after the first execution? I'm probably just not clear on how the timeout function works. Thanks for your help in advanceWilkison
This is totally incorrect and untested. The loop will never end and the setTimeout's callback will never be executed. Also, the page will become unresponsive.Gynaecocracy

© 2022 - 2024 — McMap. All rights reserved.