-3

I've been searching how to use the setTimeout function inside a loop but the documentation about this stuff seems limited, I want to make a setTimeout inside a for loop which itself is embedded in a while loop. It seems the browser executes the setTimeout only once as well as this code show it.

 var value = 0 
 var arr = [65, 59, 80, 81, 56, 70, 72, 89, 23, 11, 4, 92, 87, 84, 50, 57, 59, 44, 49, 39, 35, 32, 0]

 while(value < 10){
   const span = document.createElement('span')
   span.innerText = value
   setTimeout(() => {
     document.getElementById('spans').appendChild(span)
   },1000)
   value++
 }

can anyone explain this behaviour, and how to proceed to get setTimeout executing every inside the loop.

Is setTimeout executed in async mode.

3 Answers3

1

setTimeout does not act like a sleep. There is no pause. It registers some code to run at the time you specify. So you have 10 things all running at 1 second.

So to make your code work, you would have to multiply 1 second by the index of your loop. So they are offset

 var value = 0 
 var arr = [65, 59, 80, 81, 56, 70, 72, 89, 23, 11, 4, 92, 87, 84, 50, 57, 59, 44, 49, 39, 35, 32, 0]

 while(value < 10){
   const span = document.createElement('span')
   span.innerText = value
   setTimeout(() => {
     document.getElementById('spans').appendChild(span)
   },1000 * value)
   value++
 }
<div id="spans"></div>

Now most developers would not generate a bunch of timeouts. They would either use a queue or setInterval.

var value = 0

function nextValue() {
  const span = document.createElement('span')
  span.innerText = value
  document.getElementById('spans').appendChild(span)

  value++;
  if (value < 10) {
    window.setTimeout(nextValue, 1000);
  }
}


nextValue();
<div id="spans"></div>

or interval

var value = 0;
var timer;

function update() {
  const span = document.createElement('span')
  span.innerText = value
  document.getElementById('spans').appendChild(span)
  value++;
  if (value === 10) {
    window.clearTimeout(timer);
  }
}


timer = window.setInterval(update, 1000);
update();
<div id="spans"></div>
epascarello
  • 204,599
  • 20
  • 195
  • 236
1

//<![CDATA[
/* js/external.js */
let doc, htm, bod, nav, M, I, mobile, S, Q;
addEventListener('load', ()=>{
doc = document; htm = doc.documentElement; bod = doc.body; nav = navigator; M = tag=>doc.createElement(tag); I = id=>doc.getElementById(id);
mobile = nav.userAgent.match(/Mobi/i) ? true : false;
S = (selector, within)=>{
  var w = within || doc;
  return w.querySelector(selector);
}
Q = (selector, within)=>{
  var w = within || doc;
  return w.querySelectorAll(selector);
}
// magic under here - you can put all but end load on a separate page if desired
const arr = [65, 59, 80, 81, 56, 70, 72, 89, 23, 11, 4, 92, 87, 84, 50, 57, 59, 44, 49, 39, 35, 32, 0];
const arrCount = arr.length, spans = I('spans');
let i = 0;
let interval = setInterval(()=>{
  let span = M('span');
  span.textContent = arr[i++]; spans.appendChild(span);
  if(i === arrCount){
    clearInterval(interval); interval = undefined;
  }
}, 1000);
}); // end load
//]]>
/* css/external.css */
*{
  box-sizing:border-box; color:#000; padding:0; margin:0;
}
html,body,.main{
  width:100%; height:100%;
}
.main{
  background:#333; padding:10px;
}
#spans>span{
  color:#fff; font:bold 12px Tahoma, Geneva, sans-serif;
}
<!DOCTYPE html>
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
  <head>
    <meta charset='UTF-8' /><meta name='viewport' content='width=device-width, height=device-height, initial-scale:1, user-scalable=no' />
    <title>Title Here</title>
    <link type='text/css' rel='stylesheet' href='css/external.css' />
    <script src='js/external.js'></script>
  </head>
<body>
  <div class='main'>
    <div id='spans'></div>
  </div>
</body>
</html>
StackSlave
  • 10,613
  • 2
  • 18
  • 35
0

You need an "asynchronous" loop for setTimeout e.g.

var COUNTER = 1;
var LOOP = (DONE) => {
  setTimeout (() => {
     COUNTER++;
     console.log ("ITERATION");

     if (COUNTER === 10) {
         DONE ();
         return;
     }

     LOOP (DONE);
  }, 100);
} 

LOOP (() => {
  console.log ("DONE");
});
Bryan Grace
  • 1,826
  • 2
  • 16
  • 29