Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Most efficient way to throttle continuous JavaScript execution on a web page

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.

like image 982
dragonroot Avatar asked Mar 27 '26 05:03

dragonroot


1 Answers

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)

like image 135
hobberwickey Avatar answered Mar 29 '26 17:03

hobberwickey