Question

I'd like to continuously execute a piece of JavaScript code on a page, spending all available CPU time I can for it, but allowing browser to be functional and responsive at the same time.

If I just run my code continuously, it freezes the browser's UI and browser starts to complain. Right now I pass a zero timeout to setTimeout, which then does a small chunk of work and loops back to setTimeout. This works, but does not seem to utilize all available CPU. Any better ways of doing this you might think of?

Update: To be more specific, the code in question is rendering frames on canvas continuously. The unit of work here is one frame. We aim for the maximum possible frame rate.

Was it helpful?

Solution 4

One can use window.postMessage() to overcome the limitation on the minimum amount of time setTimeout enforces. See this article for details. A demo is available here.

OTHER TIPS

Probably what you want is to centralize everything that happens on the page and use requestAnimationFrame to do all your drawing. So basically you would have a function/class that looks something like this (you'll have to forgive some style/syntax errors I'm used to Mootools classes, just take this as an outline)

var Main = function(){
   this.queue = [];
   this.actions = {};

   requestAnimationFrame(this.loop)
}

Main.prototype.loop = function(){
   while (this.queue.length){
       var action = this.queue.pop();
       this.executeAction(e);
   }

   //do you rendering here
   requestAnimationFrame(this.loop);
}

Main.prototype.addToQueue = function(e){
   this.queue.push(e);
}

Main.prototype.addAction = function(target, event, callback){
    if (this.actions[target] === void 0) this.actions[target] = {};
    if (this.actions[target][event] === void 0) this.actions[target][event] = [];

    this.actions[target][event].push(callback);
}

Main.prototype.executeAction = function(e){
    if (this.actions[e.target]!==void 0 && this.actions[e.target][e.type]!==void 0){
        for (var i=0; i<this.actions[e.target][e.type].length; i++){
            this.actions[e.target][e.type](e);
        }
    }
}

So basically you'd use this class to handle everything that happens on the page. Every event handler would be onclick='Main.addToQueue(event)' or however you want to add your events to your page, you just point them to adding the event to the cue, and just use Main.addAction to direct those events to whatever you want them to do. This way every user action gets executed as soon as your canvas is finished redrawing and before it gets redrawn again. So long as your canvas renders at a decent framerate your app should remain responsive.

EDIT: forgot the "this" in requestAnimationFrame(this.loop)

web workers are something to try

https://developer.mozilla.org/en-US/docs/DOM/Using_web_workers

You can tune your performance by changing the amount of work you do per invocation. In your question you say you do a "small chunk of work". Establish a parameter which controls the amount of work being done and try various values.

You might also try to set the timeout before you do the processing. That way the time spent processing should count towards any minimum the browsers set.

One technique I use is to have a counter in my processing loop counting iterations. Then set up an interval of, say one second, in that function, display the counter and clear it to zero. This provides a rough performance value with which to measure the effects of changes you make.

In general this is likely to be very dependent on specific browsers, even versions of browsers. With tunable parameters and performance measurements you could implement a feedback loop to optimize in real-time.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top