ikerhurtado.com
You're in
Iker Hurtado's pro blog
Developer | Entrepreneur | Investor
Software engineer (entrepreneur and investor at times). These days doing performant frontend and graphics on the web platform at Barcelona Supercomputing Center

Webapp main loop and requestAnimationFrame()

10 Jun 2015   |   iker hurtado  
Share on Twitter Share on Google+ Share on Facebook
In this post I want to write down my findings about how to make the main loop for graphic and interactive webapps

I start noting that the typical while loop suitable for other languages/environments is not acceptable in the case of the browser platform:

while (true) {
    update();
    draw();
}

JavaScript execution environments is single-threaded. So the previous code would prevent the browser from doing almost anything else on that page. The browser will get locked up.

Window.requestAnimationFrame()

Currently, the best option in order to implement a main loop is by using the Window.requestAnimationFrame() function (well supported by the main browsers).

With this function we request the browser to draw our graphical objects at the next available opportunity. The browser takes care of synchronizing our painting with GPU and screen refresh rate. It has also could optimize performance based on load, element visibility (the user changing to other browser tab) and battery level.

We use requestAnimationFrame() by passing in a callback as argument. The callback will be just run before the next browser repaint.

The callback is passed in one single argument (DOMHighResTimeStamp), which indicates the exact time when requestAnimationFrame fired it.

function mainLoop() {
    update();
    draw();
    requestAnimationFrame(mainLoop);
}
 
requestAnimationFrame(mainLoop);

Frame rate independent loop

The way to make objects behavior frame rate independent is to calculate how much time it took between frames. As said, we can easily get the timestamp (in milliseconds) from the callback.

var lastFrameTime = 0;
 
function mainLoop(now) {
  
  var delta = now - lastFrameTime;
  lastFrameTime = now;

  // We can use delta to update 
}

Web Workers

Web Workers are the solution to the JavaScript concurrency limitation. I will not cover this subject in this post but it's very interesting: I'm going to read this article to dive into the topic next days: The Basics of Web Workers - HTML5 Rocks

As for the theme of this post, Web Workers can be useful if the tasks of update() take long enough that the frame rate drops below wanted; tasks of update() that do not need to be executed between every frame could be moved into Web Workers.

Unfortunately, Web Workers can't access data of the main thread, so they can't directly modify objects of the scene. Moving data to and from Web Workers is tedious; the better way to do it is with Transferable Objects.


POST A COMMENT: