Sunday, December 6, 2009

Javascript, sleep and closures

My wife is working on a web site and she needs a different div to show up every few seconds, ad nauseum. I hack in javascript enough to be dangerous, so every time I try something new or something I haven't done in a long time, I turn to Google. My idea for this was to simply have a loop that goes through the elements, makes one visible, then sleeps for a few seconds, show the next one, etc. So I thought I would google javascript sleep and see what came back.

What I got was, to me at least, mostly a horror show.

Lots of examples with busy waiting and splitting functions up and a lot of code that worked, in so much as it did what somebody wanted. But the code was hard to read, hard to parse, hard to update and in some cases would burn up all the cpu you let it. Knowing all of the features available in javascript I KNEW there had to be a better way, but I wasn't finding anything I thought was "good", at least in the first page of google results. Maybe I just didn't look hard enough. But at this point I figured if I thought about this for a few minutes I would come up with a better solution in less time than I could find one that pleased me. Here, after a few minutes of thought, is what I came up with




function divrotate(interval,divarray)
{
currI = 0
currLen = divarray.length
currE = document.getElementById(divarray[currI]);
currE.style.display = '';



showNext = function()
{
currE.style.display = 'none';
currI++;
if (currI == currLen) currI = 0;
currE = document.getElementById(divarray[currI]);
currE.style.display = '';
}

setInterval("this.showNext()", interval);
}



Here is what the call would look like from your HTML page

<script src="/divrotate.js" type="text/javascript">
</script>

<script type="text/javascript">
divrotate(8000, new Array("section1","section2","section3"));
</script>


what you are passing in is an interval, in milliseconds, and the array of elements (in this case DIV) that you want to iterate through. The divrotate function gets the current element and shows it, then a closure is created that will hide the current element, get the next one and show it. setInterval is used to call the closure at the interval specified by the caller.

Simple code, and it doesn't peg the CPU.

I am sure that there has got to be some other examples that are straightforward and allow the equivalent of sleep. This seems like too common of a thing to not be elegantly handled somewhere, but quick searches in scriptaculous and mootools don't show my anything promising. I see lots of forum posts with the usual "Use setInterval or setTimeout, you'll see lots of examples if you Google for it!"

I know this is far from a generic sleep example, but I hope this helps somebody that wants to do something similar. I also hope that it serves as a decent example of closures. Closures are a powerful language construct that, judiciously used, can be of great benefit when they are available. A good discussion of closers in javascript can be found here, and upon reading it there is an example that comes close to what I have done above, but the example is generic enough that it does not show the use of variables that are in scope.

No comments: