DHTML Lab - dhtmlab.com - Smooth animation using DHTML | 7 | WebReference

DHTML Lab - dhtmlab.com - Smooth animation using DHTML | 7

Logo

Smooth animation using DHTML
part 4 - setInterval()


setTimeout() delays one function call, while setInterval() calls a function repeatedly with a defined interval between each call. As seen from the test code previously, you need your function to call itself using setTimeout() to create the loop. With setInterval() that is not necessary. The function will be called at the defined interval (in milliseconds) until you tell the browser to do otherwise.

Actually neither setTimeout() nor setInterval() calls functions with specific delays. They evaluate an expression, which means that you can do other things besides calling functions. For simplicity's sake I've said that they call functions in this whole article.

Is setInterval() the solution?

At first glance one may think so. I believe there's one main advantage to setInterval() over setTimeout(): You define exactly how much time should lapse between each call of the function. Most applications I've seen using setTimeout() do some calculations first, then they move the layer and do the delay. That means the setTimeout() call comes at the tail end of the code.

We've already used 1ms as our example time for moving the layer, so let's keep to that. If you specify a 35ms delay in the setTimeout() call, and have the setTimeout() call at the end of the code, you'll get 1ms for layer movement plus 35ms for the delay. Therefore, you'll get 36ms between each call to the movement function. But, you won't know exactly how much time though, since the delay is dependant upon how long the movement function takes to run.

In other words, with our example you get 35ms + 1ms + 35ms + 1ms... If you alter the movement function so it spends more time doing calculations it will take more time between each movement of the layer, and the smoothness might disappear. setInterval(), on the other hand, has the delay set already. You've set it to call the movement function every 35ms. That delay clock ticks while the movement function runs. The result is that you'll always have a 35ms delay, as long as your movement function finishes in less than that.

Some of you might think that it's better to put the setTimeout() call at the beginning of the function. It probably is, but most scripts have some calculation first, then a conditional call to setTimeout(). This condition (usually an if() statement) is what controls the continuation of the movement. Should you wish to have the setTimeout() call early in the code you would have to figure out how to do that conditional call in a somewhat different manner (maybe use clearTimeout(), or pass a parameter to the function).

Regardless of when setTimeout() is called, the test results showed that the result with different delays is not very predictable. This is in my opinion another drawback with that solution.

setInterval() doesn't have only pros though. There's one major drawback to it too. Creating animation with setTimeout() is very easy, since the function that calculates the movement also calls setTimeout(). Therefore it's easy to stop and start the animation. This is also seen in the code used for the test. A simple if() controls the continuance of the animation. With setInterval() things become slightly more difficult. You need to use clearInterval() to stop the animation, and to do that you need to keep the return value from setInterval(). It's not really hard to do that, but it's slightly more complicated than when setTimeout() was used. Therefore your animation code might be more difficult to work with, and harder to understand for others.

Anyway, to answer the question. "Is setInterval() the solution?" Both yes and no. It is, in my opinion, a better solution than setTimeout(), but it's not God's gift to JavaScripters. The reason for this will become apparent when you look at the next test results.

setInterval() speed test

This test doesn't involve any layer movement. It's simply a quick test to see whether setInterval() actually does the job you want it to. After the setTimeout() test it's apparent that what we want is a sub-40ms delay for Windows 98 users. Can we get that?

Test setup

This test is dead simple. It has two buttons, one to start the test and one to stop it prematurely if needed. It also has two text fields. One holds the value of a variable, the other holds the time it took to finish the test once it's done. To make sure that the browser hasn't got complicated work to do all the test does is increment a numerical value by 1 until it reaches 250. Then, clearInterval() is called and the end time is calculated. Lastly, the time difference is calculated and written to the text field.

The purpose of this test is to see how small a delay it's possible to get using setInterval(). The test was run on four systems. A P2/350 running Windows 98, a Pentium 133 running Windows 95, a Pentium 75 running Linux 2.0.38 and a Mac G3/266 running MacOS 8.5. The P75 running Linux runs its X-clients on my P2's X-server, so the output shows up on the P2.

Refer to the test section to try the test out for yourself.

Test result

Browser and systemRun  #1Run  #2Run  #3
Netscape Navigator 4.08, Windows 98, P2/350138401373013740
Netscape Communicator 4.5, Windows 98, P2/350139001374013740
Netscape Communicator 4.61, Windows 98, P2/350137801368013790
Netscape Navigator 4.61, Linux 2.0.38, Pentium 75286628342827
Microsoft Internet Explorer 4 (Compatibility mode), Windows 98, P2/350140601368013730
Microsoft Internet Explorer 5, Windows 98, P2/350137801373013670
Netscape Communicator 4.5, Windows 95, Pentium 133137801384013790
Microsoft Internet Explorer 5, Windows 95, Pentium 133145501483014660
Netscape Communicator 4.6, MacOS 8.5, G3/266413541254170
Microsoft Internet Explorer 4.5, MacOS 8.5, G3/266284329302918

As you can see anything running Windows isn't going to be a pretty sight, while both the Linux and the Mac perform nicely with delays of 10-17ms. The lowest time noted on a Windows system is 13670ms. The function is called 250 times. 13670ms divided by 250 is 54.68ms. Are we getting even close to the 40ms we need for smooth animation? Not by a long shot.

Is setInterval() useless?

Do these disappointing results mean that setInterval() is useless? In my opinion: No. You won't see any improvements under Windows 95/98 using it, but on the other platforms it looks like setInterval() is very useful. As I mentioned earlier you will have to make sure your scripts use the return value, but apart from that, using setInterval() is more or less just like using setTimeout(). Compare the code for the two different solutions and you'll see that there's not much difference between them.

I've run several tests using setInterval() to perform the animation, and the results were in my opinion far better than when setTimeout() was used. "Far better" does not necessarily mean that the scripts ran faster, but that the delay between each movement of the layer was more predictable. When you set the delay to 10ms the animation finishes in around 15 seconds; at 40ms it usually ends around 60 seconds. This is the intention. You want to be able to fine tune the execution speed of the animation. Let's look at the test and the results.

setInterval() animation test

Test setup

The test setup was a lot similar to the setTimeout() test. The setTimeout() call was for obvious reasons commented out. I added a global variable "PID" which would hold the return value from setInterval() so the animation could be stopped by calling clearInterval(). The end_test() function was changed so it stops the animation before computing the end time. begin_test() only had one change: the call to setInterval() with the movement function as the parameter, and a set delay.

The setInterval() test has also been run on several systems. The G3 Mac, the Windows NT system, the Linux 2.2.12 system and the Pentium II/350 have all run the test at several delay settings. Therefore I have a good amount of information about how the delay settings affect performance across platforms.

As with all other tests, you can find this test in the test section. Lets look at the results.

Test results

1ms delay

Browser and systemRun  #1Run  #2Run  #3
Netscape Communicator 4.61, Windows 98, P2/350826608261082610
Netscape Communicator 4.7, Windows NT, P3/400150511505215061
Microsoft Internet Explorer 5, Windows NT, P3/400150321503215032
Netscape Communicator 4.6, Mac G3/26625241
Microsoft Internet Explorer 4.5, Mac G3/26630302
Netscape Communicator 4.7, Linux 2.2.12, P3/400166715041507

10ms delay

Browser and systemRun  #1Run  #2Run  #3
Netscape Communicator 4.61, Windows 98, P2/350826108267082670
Netscape Communicator 4.7, Windows NT, P3/400150511506115052
Microsoft Internet Explorer 5, Windows NT, P3/400150411503115032
Netscape Communicator 4.7, Linux 2.2.12, P3/400150381503515034

25ms delay

Browser and systemRun  #1Run  #2Run  #3
Netscape Communicator 4.6, Mac G3/26637607
Microsoft Internet Explorer 4.5, Mac G3/26638207

40ms delay

Browser and systemRun  #1Run  #2Run  #3
Netscape Communicator 4.61, Windows 98, P2/350826608267082660
Netscape Communicator 4.7, Windows NT, P3/400601266012760127
Microsoft Internet Explorer 5, Windows NT, P3/400601266013660126
Netscape Communicator 4.6, Mac G3/26660000
Microsoft Internet Explorer 4.5, Mac G3/26660513
Netscape Communicator 4.7, Linux 2.2.12, P3/400601226012160127

Comments

As you can see from these results, the performance is much more accurate across platforms, except Windows 98. It has the same appalling performance as it had in the setTimeout() test. You should also note that this test runs a lot faster on some systems (Mac and Linux) than when setTimeout() was used.

At the different delay settings the target time is logically different. A 1ms delay means the animation should finish in about 1500ms. Of the systems tested, only the Linux/Xfree combination was able to do that. With a 10ms delay the target becomes 15000ms, and both the Linux and Windows NT systems match the target. The Mac system also matches the target at 25ms (37500ms), and at 40ms all systems except Windows 98 finish at around 60000ms (target is of course 60000ms).

With a delay setting of 1ms the result reflects the maximum performance of each system. From that result you can calculate the shortest delay possible for each system. The positive thing with this test is that it shows that once you set the delay to a value larger than the shortest possible delay all systems finish close to the target time of said delay. In other words, we can predict the result, which again means we can pin-point the speed that the script will run at. Not only do we have more performance at our disposal, we can also control it.


Produced by Morten Wang and

All Rights Reserved. Legal Notices.
Created: Jan 03, 2000
Revised: Jan 03, 2000

URL: http://www.webreference.com/dhtml/column28/part-4.html