0

I am trying to loop some values, which are milliseconds. i need to run some code every xxxx second, depending on the value that he gets from the loop, but i cant get it to work, well it works but it doesn't run on time.

The code is included a reset button(the code is from a plugin, but i had to modify it)

//plugin options

  step:[
      {
          time: 6000,
          // more stuff here 
          // but we dont need 
          // it in this example
      },
      {
          time: 3000,
          // more stuff here 
          // but we dont need 
          // it in this example
      },
      {
          time: 12000,
          // more stuff here 
          // but we dont need 
          // it in this example
      }
  ]

// the loop

  var timeouts = [];
  $.each(options.step, function(i, value){

      var time =  value.time;                                                       
      timeouts.push(setTimeout(function(){

          alert('some action');

      },time*i));

  });

// reset button

  $('.stop').click(function(){
      $.each(timeouts, function (_, id) {
          clearTimeout(id);
      });
      timeouts = [];
  })
user759235
  • 2,147
  • 3
  • 39
  • 77

3 Answers3

0

My main guess here is that you aren't setting the desired timer times. You are using i * value.time as your timer time which seems odd. Do you realize that i is the index into your array, so the first time it will be zero, then 1, then 2, etc...

This will result in timer times of: 0*6000, 1*3000, 2*12000 which translates to 0, 3000, 24000.

That doesn't seem like what you would want.

In addition, Javascript in browsers is single threaded (except for webWorkers and some event side effects which are not what we're talking about here). As such, setTimeout() is not guaranteed to be accurate. If something else is running at the time a timer event fires, that timer event goes into the event queue and will be run later when the current thread of Javascript execution finishes. Thus setTimeout() will not run on time if something else is running at the time it fires.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Not quite true. http://stackoverflow.com/questions/2734025/is-javascript-guaranteed-to-be-single-threaded – Blake Regalia Sep 13 '12 at 02:08
  • @BlakeRegalia - That article has nothing to do with this context or the OP's question (e.g. the timing of `setTimeout()`). – jfriend00 Sep 13 '12 at 02:11
  • Just saying, It's good to not make bold, general statements about JavaScript without acknowledging corner cases. Thank you for editing your answer – Blake Regalia Sep 13 '12 at 02:16
  • @BlakeRegalia - by any definition I know of single threaded vs. multi-threaded, the event firings that are described in that article are still single threaded. There aren't two threads of javascript execution going at the same time. The fact that some event handler might run because you call `.focus()` is like a synchronous function call. It's not multi-threaded. It can cause problems if your code is designed poorly and is something to be aware of, but is still single-threaded. And, of course, that whole issue has nothing to do with the timing of when `setTimeout()` fires. – jfriend00 Sep 13 '12 at 02:22
0

The interval you are setting will be 0 seconds (6000 * 0), 3 seconds (3000 * 1), and 24 seconds (24000 * 2). This is because you are multiplying by the index (i). Is this the time intervals you are trying to achieve?

SonOfNun
  • 957
  • 7
  • 11
  • well if i just use on value it will work (this i used the first time) but now it has different values. – user759235 Sep 13 '12 at 01:59
  • So is the use of the indexer causing the bug? If not, please specify what you are trying to achieve with concrete intervals. – SonOfNun Sep 13 '12 at 02:00
  • well i am trying to run a piece of code every xxx seconds(depens on the values), if i use in the example above the fixed value 10000, it will run a piece of code, and wait 10 seconds before moving on, and run a piece of code and wait for 10 seconds etc etc. Yes the index isn't the right value to use i think, well not with different values. – user759235 Sep 13 '12 at 02:04
  • You do not need to multiply by indexer then. Remove that expression (`time*i`). You do not need the `time` variable either because of closure function scope : var timeouts = []; $.each(options.step, function(i, value){ timeouts.push(setTimeout(function(){ alert('some action'); },value.time)); }); – SonOfNun Sep 13 '12 at 03:00
0

time*i - this is probably your problem.

Taking for example, your provided data, you're getting these times: 6000, 3000, 12000.

Lets multiply these by i, and you'll get 0, 3000, 24000.

EDIT: As suggested in the comments below, you'd like the first value to always be zero, and resulting values to be left as they are.

Setting the delay of the timeout to i == 0 ? 0 : time would work.

Which basically means expression ? true : false;

Here's an example: http://jsfiddle.net/2ka9g/1/

ahren
  • 16,803
  • 5
  • 50
  • 70