1

I've got multiple elements on my page that fade in and out on a timer using javascript setInterval to set them in motion. I have them delayed so they are offset just slightly to create a nice cascading effect, but if you leave the page open long enough, they all catch up to one another and the timing gets all messed up (you've got to leave it for a few minutes).

I have an ugly example of the issue at CodePen here: http://www.cdpn.io/wgqJj

Again, you've got to leave the page open and untouched for a few minutes to see the problem. If you had more items on the page (5 or 10) the problem becomes even more apparent. I've also used this type of effect with several jQuery photo rotator plugins, and over time, the issue always crops up.

Is there any explanation for this?

Here is the code I'm using (I know the javascript could be cleaner):

HTML:

<p id="one">First</p>
<p id="two">Second</p>
<p id="three">Third</p>

JavaScript:

$(document).ready(function() {
  var timer1 = setTimeout(startOne,1000);
  var timer2 = setTimeout(startTwo,2000);
  var timer3 = setTimeout(startThree,3000);
});

function startOne () {
  setInterval(flashOne,3000);
}

function startTwo () {
  setInterval(flashTwo,3000);
}

function startThree () {
  setInterval(flashThree,3000);
}

function flashOne () {
  $("#one").fadeTo("slow",0.4).fadeTo("slow",1.0);
}

function flashTwo () {
  $("#two").fadeTo("slow",0.4).fadeTo("slow",1.0);
}

function flashThree () {
  $("#three").fadeTo("slow",0.4).fadeTo("slow",1.0);
}
Community
  • 1
  • 1
Dan
  • 3,750
  • 5
  • 24
  • 38
  • 3
    why not just have 1 timer, but have each effect set off at every multiple of X for that timer? Solves this problem quite well and reduces your timer clutter. – Serdalis Aug 12 '13 at 20:44
  • Not so long ago, I had a similar problem. I solved it by using single setInterval() that on interval started N setTimeout()'s. Everything appeared to be synchronized using that setInterval(), so I forgot it, but it introduced other problems, heh. – OzrenTkalcecKrznaric Aug 12 '13 at 20:45
  • possible duplicate of [setInterval timing slowly drifts away from staying accurate](http://stackoverflow.com/questions/8173580/setinterval-timing-slowly-drifts-away-from-staying-accurate) – Michael Kunst Aug 12 '13 at 20:46

3 Answers3

1

Consider using a chained setInterval instead as this give a guaranteed slot to the browser. Reference this SO post..

Currently you only use setInterval to start the animation. From there jQuery is handling the "oscillations".

Theoretically using a chained set interval should guarantee a slot, to the browser. More importantly, you can hard code the offset into the code at each interval, instead of only once at the beginning.

Community
  • 1
  • 1
Smurfette
  • 1,935
  • 2
  • 14
  • 15
1

Question has already been answered here. Quoting from the top rated answer in this topic:

it will wait AT LEAST 1000MS before it executes, it will NOT wait exactly 1000MS.

Giving an actual answer, I'd solve it like this:

$(function(){
  setTimeout(flashOne,1000);
});

function flashOne () {
  $("#one").fadeTo("slow",0.4).fadeTo("slow",1.0);
  setTimeout(flashTwo,1000);
}

function flashTwo () {
  $("#two").fadeTo("slow",0.4).fadeTo("slow",1.0);
  setTimeout(flashThree,1000);
}

function flashThree () {
  $("#three").fadeTo("slow",0.4).fadeTo("slow",1.0);
  setTimeout(flashOne,1000);
}

Like this it's not possible for the timers to mess up, as it's always delayed one second after the item before has flashed.

Community
  • 1
  • 1
Michael Kunst
  • 2,978
  • 25
  • 40
1

The setTimeout() and setInterval() functions do not guarantee that your events run exactly on schedule. CPU load, other browser tasks, and similar can and will affect your timers, therefore they are not reliable enough for your use case.

A solution for this would be asynchronous events (promises or similar) or using the event queue that jQuery supplies. That way you could either nest with callbacks, or queue them up and then fire the queue over again once it hits the last item in the queue. The .queue() API documentation page has an example of this.

tbjers
  • 564
  • 3
  • 13