Friday, January 12th, 2007

Animation with Continuations

Category: JavaScript, UI

Kris Zyp has written an article discussing the demonstration using continuations in JavaScript to facilitate writing animations with straightforward linear code.

The example is a bunch of bouncing gears that animate up and down as they bounce.

Explanation

When you click on the button, this calls the addGear function and starts a new “thread” of execution. This execution then carries out the steps of the animation in a natural linear coding sequence.

The Narrative JavaScript framework creates the ability to have multiple threads. Each time you click the button, you are effectively creating a new thread of execution. Of course the underlying JS VM is single threaded, but cooperative multithreading is possible as threads suspend execution through the continuation system.

function addGear() {

var self = this;

function makeGear() { // create the DOM img element for the gear

var gear = document.createElement(“img”);

gear.src=”images/Configurator.gif”;

gear.style.position=”absolute”;

self.gearArea.appendChild(gear);

return gear;

}

function bounceGear(gear, positionX, velocityY) { // do a single bounce

var y = 0;

gear.style.left = positionX + “px”;

do {

velocityY = velocityY – 0.4; // make a parabolic bounce

y += velocityY;

gear.style.bottom = y + “px”;

sleep(20); // pause for 20 milliseconds

} while (y > 0);

}

function waitForClick(gear) {

var notifier = gear.onclick = new EventNotifier();

notifier.wait(); // pause until the click happens

gear.onclick = null;

}

function doBouncingGear() { // this carries out the overall animation

var gear = makeGear(); // create the gear element

var x = Math.random() * 400; // random x position

var bounceVelocity = 15;

do { // do a decaying bounce

bounceGear(gear,x,bounceVelocity); // do one bounce

bounceVelocity = bounceVelocity/1.3; // the bounce/velocity decreases each time

} while (bounceVelocity > 1) // gotta stop sometime

// finished bouncing

waitForClick(gear); // wait for the user to click on it

// next in the sequence is to roll it away

var velocityX = 0;

do { // now we will roll it away

velocityX += 0.2;

x += velocityX;

gear.style.left = x + “px”;

sleep(30);

} while (x < 400); // now we will remove it gear.parentNode.removeChild(gear); } doBouncingGear(); // execute the animation } [/javascript]

Animation with Continuations

Posted by Dion Almaer at 9:08 am
9 Comments

+++--
3.3 rating from 26 votes

9 Comments »

Comments feed TrackBack URI

Isn’t “thread” another word for “object”. Creating several object instances is nothing new. I think I may have missed the point of this. Could someone help me out?

Comment by Mario — January 12, 2007

Mario: It appears to be using the Narative JavaScript package, which adds continuations to the JavaScript language: http://neilmix.com/narrativejs/doc/

These are then used to implement threaded animation, where the threads are simulated using continuations.

Comment by Simon Willison — January 12, 2007

I’ll try to help. Technically, a thread is a line of execution which at any moment consists of a call stack. A call stack is a stack where each entry is a frame. A frame holds all of your local variables, a code pointer, and information about what code is currently being executed. Normally the operating system, or your VM (for Java) keeps track of all of this (and modern architecture is built to handles aspects of the stacking, and keeping track of the code pointer). The OS also handles multi-thread and thread switching so that different threads can coexist.
In my demonstration there is JavaScript that is basically handling the call stacks/frames, and context switching (which is cooperative like Windows 3.1, not preemptive). Everytime you start a new “thread” you are starting the function, but the function does not finish until the ball is done bouncing and you have clicked the ball to roll at away. By clicking the button multiple times, you can have the function executed several times at once. Normally, you can’t do this in JavaScript because it is single threaded (a function must finish before going on the next), but the Narrative JavaScript framework lets us effectively have multiple threads, that is multiple line of executions with their own call stacks operating independently at the same time. Hope that makes sense, I know it is kind of confusing.

Comment by Kris Zyp — January 12, 2007

Does this method result in multiple setTimeout calls, two per gear? (It looks like it, but I didn’t dig in too far.) My experience has been that it’s most efficient to have only one timeout or interval call running, with a loop that would iterate through all items being animated (related article.) I like the approach taken here as it’s what many people would prefer to do, but I think it may not run as smoothly as a single loop (animation example.) I believe the YUI library and others are based on similar single-timer/interval approaches, though I could be wrong. ;)

Comment by Scott Schiller — January 12, 2007

Thanks for the info. JavaScript is single threaded by nature. Do you get around this by using iframes or some other tech. to achieve multiple threads? Or is it a perception of multiple threads but in reality its still queing them. Also if this is multi threaded this would seem to give a performance boost. Have any studies been done to suggest this?

Comment by Mario — January 12, 2007

Mario: Yes, the continuations framework provides the “simulation” of multiple threads within a singled threaded environment (it is not done with iframes or anything), and in essence they are queued although in reality the framework just keeps track of call stacks, and the browser does the queuing through the event handling mechanism in the VM/browser. Therefore, I would not expect any performance boost (although I believe that when programming is simplified that the reduction in bugs usually results in less issues causing performance problems. Automated GC is a classic example of that).
Scott: There are not two setTimeouts per gear, just one, but if there is more than one gear bouncing than you have more than one setTimeout at once (1 per gear). And understand what you are saying about having a centralized interval handler that does the setTimeouts and delegates all the animation that must take place within one “frame” or clock tick. That is probably slightly faster, however, that is a completely different approach than what I using. The idea of this demo is to provide linear coding, and to avoid the complexities of assimulating all animations into a centralized animator. Also, I would think that the overhead of multiple setTimeouts would be negligible compared to the other things go on. Namely, DOM updates seem to be the operation appears to me take the most processing time.

Comment by Kris Zyp — January 12, 2007

Kris: Good points. On my P4 2.8 GHz desktop, the animation lagged a fair bit when about 8 gears were running under Firefox, so this would be 8 setTimeout calls and may help to explain the speed issue. Unfortunately, timeouts seem to really incur a cost to execute (sort of like eval?)
Kudos on the linear approach you’re taking with the demo, it’s a sorely-missing aspect of JS which would be nice to have. I also agree on the DOM/reflow aspect being where most of the heavy lifting is done.

Comment by Scott Schiller — January 12, 2007

Yes, multiple gears does slow things down, and as articles you cited discuss, performance can be improved by multiple parts of the animation in from one setTimeout trigger. However, I am pretty sure that is not the setTimeout that causes the performance degradation. I think that the reason is that whenever there is a break in execution, the browser takes the opportunity to update view based upon DOM changes. When multiple setTimeouts occur and each DOM update is done separate than the browser makes more frequent updates to view. If multiple DOM changes take place with one sequence of JavaScript execution, the browser only needs to do a single view update and this is much faster.
My code still doesn’t deal with this issue, but it is not intended to be a high performance technique for animation, but simply a demonstration of the simplicity of using continuations

Comment by Kris Zyp — January 12, 2007

Great stuff, first of all. Narcisis is brilliant. One question, though… what happens if you have to selectively abort the threads of execution of a few continuations (i.e., in a sleep(30000)? Does your library have any API for that? I supposed a “broken” sleep() could throw an exception which the user’s code could handle.

Comment by Question — January 14, 2007

Leave a comment

You must be logged in to post a comment.