4

I know there is an Answer for this But!! All The Answers covered with only one setTimeout in the loop this Question Looks relevant to me How do I add a delay in a JavaScript loop? But in my Scenario I Have two setTimeout in the Script, How can this be implemented correctly with timing !! The Program works correctly but the timing what I want is not correct !!!

function clickDate(i)
{
  setTimeout((function(){
  alert("4");
  })(),2000);
}
function clickButton(i)
{
  setTimeout((function(){
  alert("5");
})(),4000);
}

function doEverything(i)
{
  clickDate(i);
  clickButton(i);
}
for(var i = 0; i < 4; i++)
{
 doEverything(i);
}
Xameer
  • 105
  • 2
  • 11
  • 2
    Look _very closely_ at the syntax you're using for the callbacks. It is **not** the same as that used in the post you link to. – Mat Jul 20 '17 at 12:23
  • 2
    don't use `(function(){ alert("5"); })()`, being an immediately executed function, it will be executed as soon as the code reaches it, and passes the result as a callback. use `function(){ alert("5"); }` – Kaddath Jul 20 '17 at 12:24
  • 1
    Okay I'm using callback function to out the the alerts in order 4 5 4 5 4 5 4 5 4 5 but without using callback function I'm getting 4 4 4 4 and then 5 5 5 5. – Xameer Jul 20 '17 at 12:40

5 Answers5

8

You're immediately calling the function when you pass it to setTImeout. Remove the extra parenthesis.

function clickDate(i)
{
  setTimeout(function(){
  alert("4");
  },2000);
}
function clickButton(i)
{
  setTimeout(function(){
  alert("5");
},4000);
}

function doEverything(i)
{
  clickDate(i);
  clickButton(i);
}
for(var i = 0; i < 4; i++)
{
 doEverything(i);
}

EDIT

It's a little unclear what exactly it is you want your code to do seeing as you're passing i into your function I assume you want to use it somehow. Currently you're creating timeouts that will all launch at once. You'll need to stagger the delay times if you want them to launch in sequence. The code below logs a "4" every 2 seconds and a "5" every "4" seconds by multiplying the delay time by i+1.

// Currently this code displays a 4 every 2 seconds and a 5 every 4 seconds
function clickDate(i)
{
  setTimeout(function(){
  console.log("4");
  },2000 * (i+1));
}
function clickButton(i)
{
  setTimeout(function(){
  console.log("5");
},4000 * (i+1));
}

function doEverything(i)
{
  clickDate(i);
  clickButton(i);
}
for(var i = 0; i < 4; i++)
{
 doEverything(i);
}
Khauri
  • 3,753
  • 1
  • 11
  • 19
  • This will also have timing problem. – Yash Ganatra Jul 20 '17 at 12:30
  • Your Answers Solves the Timing Problem but the alerts are not in sync !! the out put is 4 4 4 4 and then 5 5 5 5 . – Xameer Jul 20 '17 at 12:34
  • OP wasn't clear about what he wanted the code to do so I tried not to assume too much. However using alert is a bad idea because it won't give you a good idea about how the timing actually works out. Furthermore your for loop will create a bunch of timeouts basically all at once.and probably not at intervals like you're expecting. (For ease I would just multiply the timeout time by i+1). – Khauri Jul 20 '17 at 12:37
  • Okay if I use other than Alerts, let's say a "Click" Event will it be in Sync. – Xameer Jul 20 '17 at 12:42
  • Just use `console.log` and open up the developer's console. (ctrl+shift+i on Chrome). It'll be much easier to see when the messages come in and in what order without having to click the alert away each time. – Khauri Jul 20 '17 at 12:48
  • I updated my answer with what I think you were going for. But if that's not exactly it then I think Yash Ganatra has provided an answer that will print a "4" after two seconds, then a "5" 4 seconds after the "4". rahtern than a "4" every two seconds and a "5" every 4 seconds. (i.e., the timeouts depend on each other vs being independent of eachother) – Khauri Jul 20 '17 at 12:57
2

Hello I think you havent read documentation about javascript. It's asynchronous and it will not wait for the event and continue the process. I will give the answer but I highly recommend to read about Javascript it's good for you only here you will get timing problem because your both the function will be called at the same time. Let me give you the example.

function clickDate(i,callback)
{
  setTimeout(function(){
  alert("4");
  callback();//this will call anonymous function in doEverything
  },2000);
}
function clickButton(i)
{
  setTimeout(function(){
  alert("5");
},4000);
}

function doEverything(i)
{
  console.log("In loop index is " , i);
  clickDate(i,function(){
       clickButton(i);
  });
  //look closely here I have passed the function in changeData and will call that funtion from clickDate
  console.log("In loop terminating index is " , i);
}
for(var i = 0; i < 4; i++)
{
 doEverything(i);
}

So here console log will make you clear about asynchronous functionality. You will see that for loop terminates as it continues it's work and easily completed in 2 seconds so before your first alert for loop will complete it's iteration.

Hopefully this will help.

Yash Ganatra
  • 468
  • 2
  • 12
1
function functionName() {
    setTimeout(function(){ //Your Code }, 3000);
}

Try this one.

litelite
  • 2,857
  • 4
  • 23
  • 33
Jaimin Raval
  • 146
  • 5
0

you are calling the callback immediately by adding () to the end of function .

you need to pass the callback with timeout and it will be call for you

setTimeout(function(){
alert('hello');
} , 3000);
Ali Faris
  • 17,754
  • 10
  • 45
  • 70
0

Your approach to mocking asynchronous behavior in JavaScript with setTimeout is a relatively common practice. However, providing each function with its own invocation of setTimeout is an anti-pattern that is working against you simply due to the asynchronous nature of JavaScript itself. setTimeout may seem like it's forcing JS to behave in a synchronous way, thus producing the 4 4 4 4 then 5 5 you are seeing on alert with iteration of the for loop. In reality, JS is still behaving asynchronously, but because you've invoked multiple setTimeout instances with callbacks that are defined as anonymous functions and scoped within their own respective function as an enclosure; you are encapsulating control of JS async behavior away from yourself which is forcing the setTimeout's to run in a strictly synchronous manner. As an alternative approach to dealing with callback's when using setTimeout, first create a method that provides the timing delay you want to occur. Example:

// timer gives us an empty named "placeholder" we can use later
// to reference the setTimeout instance. This is important because
// remember, JS is async. As such, setTimeout can still have methods
// conditionally set to work against it.

let timer 

// "delayHandler", defined below, is a function expression which when
// invoked, sets the setTimeout function to the empty "timer" variable
// we defined previously. Setting the callback function as the function 
// expression used to encapsulate setTimeout provides extendable control
// for us later on however we may need it. The "n" argument isn't necessary,
// but does provide a nice way in which to set the delay time programmatically
// rather than hard-coding the delay in ms directly in the setTimeout function
// itself.

const delayHandler = n => timer = setTimeout(delayHandler, n)

Then, define the methods intended as handlers for events. As a side-note, to help keep your JS code from getting messy quickly, wrap your event handler methods within one primary parent function. One (old school) way to do this would be to utilize the JS Revealing Module Pattern. Example:

const ParentFunc = step => {

  // "Private" function expression for click button event handler.
  // Takes only one argument, "step", a.k.a the index
  // value provided later in our for loop. Since we want "clickButton"
  // to act as the callback to "clickDate", we add the "delayHandler"
  // method we created previously in this function expression.
  // Doing so ensures that during the for loop, "clickDate" is invoked
  // when after, internally, the "clickButton" method is fired as a
  // callback. This process of "Bubbling" up from our callback to the parent
  // function ensures the desired timing invocation of our "delayHandler"
  // method. It's important to note that even though we are getting lost
  // in a bit of "callback hell" here, because we globally referenced 
  // "delayHandler" to the empty "timer" variable we still have control
  // over its conditional async behavior.

  const clickButton = step => {
    console.log(step)
    delayHandler(8000)
  }

  // "Private" function expression for click date event handler
  // that takes two arguments. The first is "step", a.k.a the index
  // value provided later in our for loop. The second is "cb", a.k.a
  // a reference to the function expression we defined above as the
  // button click event handler method.

  const clickDate = (step, cb) => {
    console.log(step)
    cb(delayHandler(8000))
  }

  // Return our "Private" methods as the default public return value
  // of "ParentFunc"

  return clickDate(step, clickButton(step))
}

Finally, create the for loop. Within the loop, invoke "ParentFunc". This starts the setTimeout instance and will run each time the loop is run. Example:

 for(let i = 0; i < 4; i++) {

   // Within the for loop, wrap "ParentFunc" in the conditional logic desired
   // to stop the setTimeOut function from running further. i.e. if "i" is 
   // greater than or equal to 2. The time in ms the setTimeOut was set to run
   // for will no longer hold true so long as the conditional we want defined
   // ever returns true. To stop the setTimeOut method correctly, use the 
   // "clearTimeout" method; passing in "timer", a.k.a our variable reference 
   // to the setTimeOut instance, as the single argument needed to do so.   
   // Thus utilizing JavaScript's inherit async behavior in a "pseudo" 
   // synchronous way.

   if(i >= 2) clearTimeout(timer)
   ParentFunc(i)
 }

As a final note, though instantiating setTimeOut is common practice in mocking asynchronous behavior, when dealing with initial invocation/execution and all subsequent lifecycle timing of the methods intended to act as the event handlers, defer to utilizing Promises. Using Promises to resolve your event handlers ensures the timing of method(s) execution is relative to the scenario in which they are invoked and is not restricted to the rigid timing behavior defined in something like the "setTimeOut" approach.

DaneTheory
  • 282
  • 3
  • 16