Tuesday 22 May 2018

Async/await with Animations

Years ago I had fun coding an animation matrix (the sample has been moved here). Most cases involved a sequence of animations, each one starting after the previous one had finished. It was one more case where I had to simulate an asynchronous loop, where at the end of each "iteration" I would callback into an "orchestrator function" that would launch the next iteration. I realized that now that we have async/await, this could be done in a much more straight forward way, so I've prepared some sample code.

For the kind of animation that I'm doing it would have been more simple to just animate divs rather than drawing squares on a canvas, but lately I've been playing around with particle systems on a canvas, and I've preferred to continue with the canvas route.

Whatever item we are animating, the thing is that starting the animation should return a Promise that will get resolved when the animation completes. For this sample I'm animating a square that falls from the top to the bottom of the canvas and bounces a couple of times until it stops. You can see it here. The code (yep, I've jumped into the TypeScript trend) looks like this:


abstract class AnimationItem{
 currentPosition:Vector;
    endPosition:Vector;
    moving:boolean;
 resolveCurrentAnimationFunc:any;

 public abstract update():void;
 public abstract draw():void;
 
 public animate():Promise<void>{
  this.moving = true;
        return new Promise<void>((res, rej) => {
            this.resolveCurrentAnimationFunc = res;
        });
    }
}


//in our child, concrete class:
    public update():void{
        if(!this.moving){
            return;
        }

        this.ySpeed += this.gravity;
        //this.logger.log("speed: " + this.ySpeed + ", pos:" + this.currentPosition.y + ", " + this.acceleration);
        this.currentPosition.y += this.ySpeed;
        if(this.currentPosition.y >= this.endPosition.y){
            //let's place it just in the limit
            this.currentPosition.y = this.endPosition.y;
            if(this.bounces > 0){
                this.bounces--;
                this.ySpeed = -1 * this.ySpeed/2;
                this.logger.log("bouncing: pos:" + this.currentPosition.y + ", speed: " + this.ySpeed + ", " + this.acceleration);
            }
            else{
                //stop it
                this.moving = false;
                this.resolveCurrentAnimationFunc();
            }
        }
    }

So we have an animate method that returns a newly created Promise and stores in our class a reference to the resolve handle of this Promise. The update method takes care of updating the position of the object and resolving the Promise once the final position is reached.

I'm animating several of these items (rows and columns), one after another. With the power of async/await our code is so simple as just writing normal loops like this:

for (let y=0; y<2; y++){
        for (let x=0; x<3; x++){
            let item:AnimationItem = new FallingSquare(ctx, 
                new Vector(x * size, 0), //currentPosition:Vector, 
                new Vector(x * size, canvas.height - (size * (y + 1))), //endPosition:Vector,
                0, //speed:number, 
                size,
                "red",
                logger);
            
            animationSystem.addItem(item);   
            await item.animate();
        }
    }

I've uploaded along with the transpiled and bundled javascript file the original typescript source code and the source map, so to see the full code just launch the debugger!

Friday 18 May 2018

Foreach Async Gotcha

Today I came up with an interesting gotcha with async/await. I transformed a normal for loop containing await calls into an Array.prototype.forEach call, and realised that it was not working properly. Let's see:

Let's say that we have this nice async loop:

//asynchrnous function returning a Promise
function formatTextAsync(txt){
    return new Promise((res, rej) => {
        setTimeout(()=> res(txt.toUpperCase()),
         2000);
    });
}

async function loop1(){
    console.log("loop1 start");
    let items = ["bonjour", "hi", "hola"];
    for (item of items){
        console.log(Date.now() + " input: " + item);
        item = await formatTextAsync(item);
        console.log(Date.now() + " output: " + item);
    }
    console.log("loop1 end");
}

console.log("before main");
loop1();
//loop2();
//loop3();
console.log("after main");

// before main
// loop1 start
// 1526678289508 input: bonjour
// after main
// 1526678291514 output: BONJOUR
// 1526678291515 input: hi
// 1526678293518 output: HI
// 1526678293518 input: hola
// 1526678295521 output: HOLA
// loop1 end

If we decide to move the loop body into an Array.prototype.forEach method call, the output is quite different:

async function loop2(){
    console.log("loop2 start");
    ["bonjour", "hi", "hola"].forEach(async (item) => {
        console.log(Date.now() + " input: " + item);
        item = await formatTextAsync(item);
        console.log(Date.now() + " output: " + item);
    });
     console.log("loop2 end");
}

// before main
// loop2 start
// 1526678543105 input: bonjour
// 1526678543109 input: hi
// 1526678543109 input: hola
// loop2 end
// after main
// 1526678545109 output: BONJOUR
// 1526678545111 output: HI
// 1526678545111 output: HOLA

So in the second code, the next iteration is launched without waiting for the async call in the previous iteration to complete. This means that the async calls end up running in parallel rather than in sequence.

The explanation for this behaviour is quite simple. We've moved the loop body containing the async call into a new function that we've marked as async, but, is anyone awaiting for this new function?, the answer is No, so the next iteration is started without waiting.

We can guess that the implementation of Array.forEach is something along these lines:

Array.prototype.forEach = function (fn) {
    for (let item of this) { fn(item) }
}

In order to get the correct async behaviour that we have when using a normal loop, we would need something like this:

Array.prototype.forEachAsync = async function (fn) {
    for (let item of this) { await fn(item) }
}

Lisbon Documentaries

Some months ago I wrote about how a lovely city Lisbon is. I've recently watched 2 pretty interesting documentaries showing 2 complementary views of the city, and I've thought that it would be nice to share them here.

DW (Deutsche Welt) has some excellent documentaries in English, dealing with a broad range of topics: social, politics, technology, travel... This one shows a really interesting portrait of life in Lisbon. It's from 2013 I think, which seems to me like the time when Lisbon was starting to become a trendy city attracting foreigners not just for regular vacation, but for longer/permanent stays. In some of the amazing panoramas one can see some construction cranes, but little to do with the huge number of them that I could see last November. I really enjoy when I see in films or documentaries places that occupy a place in the memories of my heart, and this documentary has quite a few of them.

This one from 2018 by BBC puts its focus on the artistic side of the city and how it has been modelled by the Portuguese history. I share with the female host the fascination with the Mosteiro dos Jeronimos and its Manueline gothic. I remember how amazed and excited I felt in my first time there. On the other side, though I understand that they want to focus on Portuguese art, I find it hard to believe that their filming in the Museu Nacional de Arte Antiga has not included any reference to the most amazing work located there, the Temptation of Saint Anthony. For sure Hieronymus Bosch has little to do with the History of Portugal, but any art lover visiting Lisbon should not miss spending quite a while in front of this heartbreaking Triptych.

Thursday 10 May 2018

La Charia au Paradis

Some weeks ago I watched La Charia au Paradis a quite disturbing documentary about Maldives, that small island country in the Indian Ocean. Until then my basic knowledge about these islands could be summed up in these few points.

  • An idyllic tourist destination
  • One of the places that was hit hard by the 2004 tsunami
  • One of those places particularly threatened by the sea level rise (the whole country could just disappear)

I had no idea about the politics of these islands, and though I had the impression that it was mainly a muslim country, I was not aware of particular problems caused by the "religion of peace". Well, I was quite far from the true. In the last years fundamentalist Muslims have taken control of the country and are imposing their madness to the rest of the population. The law system is based on the shariah, and Saudi Arabia has been more than happy to host and train Maldivian guys in the "true Islam" so that they can return to the islands to teach/impose their Medieval learnings to a population that until recently was for the most part rather moderate. Hum, lovely Saudi Arabia, exporting love an tolerance not only to the European "Quartiers Sensibles", but also to peaceful, idyllic islands.

For the moment, given that the whole country lives on tourism, shariah law is not applied to the foreigners that fill the touristic resorts, but that could be changing in the future. Maybe they are planning to replace Western amoral couples with Saudi families. In the meantime, if I were a tourist I would be a bit scared that one day one bunch of beardy Islamist could decide to raid one of the resorts...