0

I'm trying to add a delay in one of my loops but I get unexpected results. I've looked at many similar questions but since I'm trying to learn javascript I want to know why this isn't working and how I can get it to work.

If you look at the script below, shouldn't it go like this:

  1. cars[1]
  2. sleep(); (wait 3 sec then return)
  3. add 1
  4. Run the script again
  5. cars[2]
  6. etc ...

With output:

  1. Saab
  2. Waiting 3 seconds...
  3. Volvo
  4. Waiting 3 seconds...
  5. etc ...

But the output I receive is:

  1. Saab
  2. Volvo
  3. BMW
  4. Done

(Waiting 3 seconds here)

  1. Waiting 3 seconds...
  2. Waiting 3 seconds...
  3. Waiting 3 seconds...

Am I stupid or is javascript working entirely different than C++ and assembly?

var nr = 0;
const qty = 3;

function script() {
main();
console.log("Done");
}

function main() {
var cars = ["Saab", "Volvo", "BMW"];
  if (nr !== qty) {
    console.log(cars[nr]);
    sleep();
    nr++;
    main();
  }
  else {
      return;
  }
 }
 
function sleep() {
    setTimeout(function () {
    console.log('Waiting 3 seconds...');
    return;
  }, 3000);
}
<!DOCTYPE html>
<HTML>
    <HEAD>
    </HEAD>
    <BODY>
    <button onclick="script()">Run Script</button>
    </BODY>
</HTML>

5
  • 3
    Because setTimeout doesn't block the script execution. Commented Oct 30, 2020 at 19:59
  • 1
    because what inside the setTImeout(function() will executed after 2000ms Commented Oct 30, 2020 at 20:01
  • you want to pass a callback to setTimeout from sleep, like everyone said Commented Oct 30, 2020 at 20:02
  • I would try turning your loop into a recursive function and calling it from setTimeout(). function recursiveFn() { doStuff(); setTimeout(recursiveFn,3000) } BTW, your sleep() fn says "waiting 3 seconds" but it's only set to for 2000ms or 2s. Commented Oct 30, 2020 at 20:03
  • Oh ok, got it. Thanks! (yea I changed the sleep function to 3000 lol) Commented Oct 30, 2020 at 20:06

5 Answers 5

2

The setTimeout() function doesn't block. It calls the function passed to it after the time out. You can just tell it to call main.

function main() {
    var cars = ["Saab", "Volvo", "BMW"];
    if (nr !== qty) {
        console.log(cars[nr]);
        nr++;
        sleep(3, main);
    }
}

function sleep(timeout, func)
{
    console.log(`Waiting ${timeout} seconds...`);
    setTimeout(func, timeout * 1000);
}
Sign up to request clarification or add additional context in comments.

Comments

2

The joys of asynchronous programming.

Now's maybe a good time to head into MDN and learn about promises, and async await

async function main() {
var cars = ["Saab", "Volvo", "BMW"];
  if (nr !== qty) {
    console.log(cars[nr]);
    await sleep();
    nr++;
    main();
  }
  else {
      return;
  }
 }
 
async function sleep() {
return new Promise(resolve=>{
    setTimeout(function () {
    console.log('Waiting 3 seconds...');
    resolve();
  }, 3000);
});
}

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

1 Comment

Thank you very much!
1

Hi bro the setTimeout doesn't block the script execution. and javascript is diffident from C++ at script execution. it's so easy with js

cars.forEach(function(value,index){
         setTimeout(function(){
              console.log(value);
              console.log('waiting 3 s');
          },index*3000)
});

Comments

1

setTimeout does not interrupt the main thread. Instead, it registers your callback function and continues executing upcoming lines.

To get your desired output, we need to have callbacks here and there. This is something called asynchronous programming in JavaScript land. You could also make use of Promise to simplify your code.

var nr = 0;
const qty = 3;

function script() {
  main(function () {
    console.log('Done');
  });
}

function main(callback) {
  var cars = ['Saab', 'Volvo', 'BMW'];

  sleep(function loop() {
    console.log(cars[nr++]);

    if (nr === qty) {
      // call the callback function
      callback();
    } else {
      // or do the loop
      sleep(loop);
    }
  });
}

function sleep(callback) {
  setTimeout(function () {
    console.log('Waiting 3 seconds...');
    callback();
  }, 3000);
}

1 Comment

Didn't know it didn't pause the script execution! Thank you very much for the answer!
1

you have to learn more about asyncronous functions to better understand this issues but here is an exemple should work for you :

var nr = 0;
const qty = 3;

  function script() {
       const callback = ()=>{
         console.log('Done')
       }
    main(callback)
 

}

 async function  main(cb) {
 
     var cars = ["Saab", "Volvo", "BMW"];

       if (nr !== qty){
    console.log(cars[nr]);
         
     await sleep()
    nr++;
     main(cb);
  }else{
       cb()
  }

  
  
 }
 
 function sleep() {
     console.log('Waiting 3 seconds...')
return new Promise((resolve)=>{
      setTimeout(function () {
      
    resolve()
   
  }, 3000);
})
}
script()

also try to never use global object and works always with functions params

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.