Sonalk
Sonalk

Reputation: 79

Javascript - Delay in loop | Why isn't this working?

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>

Upvotes: 0

Views: 191

Answers (5)

001
001

Reputation: 13533

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);
}

Upvotes: 2

nafaa jamel
nafaa jamel

Reputation: 56

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

Upvotes: 1

shotasenga
shotasenga

Reputation: 979

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);
}

Upvotes: 1

Abdelrhman  Gemi
Abdelrhman Gemi

Reputation: 171

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)
});

Upvotes: 1

cWerning
cWerning

Reputation: 633

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

Upvotes: 2

Related Questions