2007-03-20

ECMAScript : RendezVous mechanism

A common need when I program some concurrency stuffs in ECMAScript is to be able to tell when the last event of a series of events happened.

The dumb way of doing things is to set a variable to true each time an event occur. If all variables are true I know that all events have occured. This is not a very elegant technic and that generate a lot of code.

I was thinking about a more convenient solution called "RendezVous". I have called this function a "RendezVous" in memory of ADA language (RIP) that provide a syncronisation mechanism of the same name. Here is my solution :

function rendezVous()
{
    // number of functions : shared between decorator
    var nbf = (arguments.length-1)/2;
    // the last one is the callback
    var callback = arguments[arguments.length-1];
    for(var i=0;i<arguments.length-1;i=i+2)
    {
        var obj = arguments[i];
        var func = arguments[i+1];
        // replace the old function by a decorated function
        obj[func]=rendezVousDecorator(obj,func,obj[func],
            function(){--nbf;return nbf;},callback);
    }
}
function rendezVousDecorator(obj,func,old,dec,callback)
{
    return function()
    {
        // put the old function back
        obj[func]=old;
        // run the old function
        obj[func]();
        // decrement the counter and launch
        // the callback if it's the last function
        if(dec()==0)
            callback();
    }
}
// tests
var out = document.getElementById("out");
var obj1 = {func1:function(){out.innerHTML+="func1, "}}
var obj2 = {func2:function(){out.innerHTML+="func2, "}}
func3 = function(){ out.innerHTML+="func3, " };

// I construct the "RendezVous"
rendezVous(obj1,"func1",obj2,"func2",this,"func3",
    function(){out.innerHTML+=" Rendez vous !!!\r\n"});

// I launch the "RendezVous" functions
obj1.func1();
obj2.func2();
obj1.func1();
// The "RendezVous" callback must be launched after this one
func3();

This "RendezVous" mechanism can be very useful with Ajax calls. For the sake of simplicity I don't have use these.

Run this code