UPDATE: It’s been pointed out in the comments that because most LCD displays have a refresh rate of 60hz, attempting to get anything higher than 60fps is mostly pointless. However, the method I discuss isn’t confined to just FPS but is rather about removing the inherent delay when using timers while still allowing the browser to update UI and allow user interaction. Also, if you have code running at 20fps this method may help you glean a few more frames each second.
UPDATE 2: Apparently Internet Explorer 10 will be implementing the setImmediate() function which would be the best method to use for quick loops. I can’t find any info on whether Firefox or Chrome is planning on adding this method anytime soon, but I would suspect it will be included in their builds soon enough. Here’s the W3C spec.
Next idea on minifying the delay does remove timers altogether while still providing a way for the browser to continue updating its interface and executing other code on the page. This method relies on using a call to window.postMessage This is a wonderful new method defined in HTML5 which allows one window to communicate and pass messages to another window. At the end of my main() loop I can call window.postMessage(”, ‘*’); – this simply passes an empty message to the current window. If this was everything, my code would stop executing at the end of the main() loop. However, by adding an event listener (window.addEventListener(‘message’, main, false);) I also catch any messages posted to my window by immediately calling my main() loop. The side affect of this is that in between making the postMessage() call and having my main() loop executed again, the browser can update its UI and execute any other scheduled code, thereby providing no interruption to the user while still having my main() loop executed immediately. In my test script, this method executes my main() loop at 880fps in firefox and an astounding just-under-1000fps in Chrome.
That’s all well and good but it’s just a test script, right? These sort of numbers can’t in anyway carry over to an actual game execution loop can they? My game runs at ~63fps when using setTimeout(main, 1). When I switch that out for the postMessage() method the fps jumps up to ~330fps. However (and unfortunately), this speed is actually more taxing for my processor which makes the browser somewhat less responsive to user input: from the user’s point of view, the experience is lessened.
Takeaway: While not a perfect (or great) fit for a main() loop, using the postMessage function can allow you to execute tight and/or infinite loops without degrading user experience. These could be used in addition to a main() loop, perhaps increasing the quality of collision detection, or by performing some repeating non-scheduled task such as pathfinding.
The code I ran for the tests is up on jsFiddle.
Here are the test results for the four separate methods used. System 1 has an Intel Core2 Duo E8400 @ 3.00GHz with 2GB of RAM running XP service pack 3. System 2 has an Intel Core i5 @3.2GHz with 4GB of RAM running on Win7 32bit.
|Pure Timers||requestAnimationFrame||Interupted Loop||postMessage|
|System 1 – Firefox 4||95fps||58fps||206fps||880fps|
|System 1 – Chrome 11||206fps||60fps||206fps||999fps|
|System 1 – IE 8||64fps||64fps (using polyfill)||64fps||- *|
|System 2 – Firefox 3.6||91fps||91fps (using polyfill)||856fps||995fps|
|System 2 – Chrome 12||250fps||63fps||250fps||999fps|
|System 2 – Safari 5||95fps||95fps (using polyfill)||141fps||999fps|
|System 2 – IE 9||401fps||402fps (using polyfill)||452fps||973fps|