AsyncResult 2/3

async-book

Ok, as promised I have extended and hopefully made more usefull, my AsyncResult mechanism, as presented in the first instalment of this javascript ‘soap’ ;)

For AsyncResult 1/3 please click here.

For AsyncResult 3/3 please click here.

Without further obfuscations here is the code :

//
// V 8 
// MIT (c) 2009 by DBJ.ORG
//
// caling example
//  spawn({ 'worker': w1, 'delay': 1000, 'callback': on_async_finished }, 1, 2, 3)
//
// Mandatory arguments :
// 1:JSON object where
// worker   [mandatory] function pointer of the worker to execute asynchronously
// delay    [optional]  delayed execution time unit in microseconds, 
//                       if null then 1.
// callback [optional]  called 'back' when worker is done with 
//                      AsyncResult instance
//                      as its only argument
// [optional]
// any arguments required by worker function
//
function spawn ( )
{
  var AsyncResult = function(args_) {

    var FP = args_[0].worker;
    var tu = parseInt(args_[0].tu === null ? 1 : args_[0].tu);
    tu = (tu  >  spawn.maxdelay ? spawn.maxdelay : tu)
    var CB = args_[0].callback;

    this.toString = function() {
    // return JSON formated object exposing private properties
    // this idiom exposes private properties without get/set methods
        return "{ done: " + that.done + ", retval: " + that.retval + ", id: " + that.tid + " }";
    }
    // preserve the current instance aka 'this'
    var that = this;
    // create properties on the curent instance
    that.done = false;
    that.retval = null;
    that.tid = null;
    that.CB = CB;
    // transform arguments to array and cut the first element
    // thus leaving arguments for FP
    that.args = Array.prototype.slice.call(args_).slice(1);
    // this private method is delay executed *outside* of the context of the current instance
    // it is executed in the context of the 'global space' aka the 'window' object
    function doit(x) {
        try {
            // execute FP(args), and preserve its return value
            that.retval = FP.apply(null, that.args);
            // signal that execution finished ok
            that.done = true;
        } catch (x) {
            // FP() caused an exception
            that.retval = x.message; // for caller to see which one
            // signal that execution finished in errror
            that.done = false;
        }
// for testing purposes show the state of the AsyncResult instance
    if (spawn.log) spawn.log("AsyncResult::doit()\n\n" + that);
// use clearInterval to release the timer ID
    clearTimeout(that.tid);
// call the callback , if given
    if (that.CB) {
        var cb_tid = setTimeout(function(x) {
            clearTimeout(cb_tid);
            try { CB(that); } catch (x) { /* ignore callback exceptions */ }
        }, 1);
    }
   }
// delay doit() execution , 
// in the context of the 'window' object
        that.tid = setTimeout(doit, tu);
    }
       return new AsyncResult( arguments ) ; 
// immediate instance return
// FP() to be delay-executed in 'tu' microseconds
      }
// maximum number of seconds spwan will do
      spawn.maxdelay = 60 * 1000; // aka one minute
// if null will not be used
// otherwise must be a function with a single string argument
      spawn.log = null ;

I hope the comment on the top explains sufficiently well how to use this. In this version, one can pass any number of legal javascript arguments to the spawn function, to be passed onto the worker . And also one can assign a function which will be called “back” , from inside AsyncResult after worker execution has finished.

Here is the simple example of using AsyncResult and spawn() :

function on_async_finished(async_result) {
    dbj.log("Async finished: " + async_result);
}
   function w1(a, b, c) { return [a, b, c];
}
 dbj.log("Async started: " +
  spawn({ 'worker': w1, 
          'delay': 1000, 
          'callback': on_async_finished }, 
           1, 2, 3)
);

This mechanism enables use of one function to be called on finish, or use of many callback functions, one for each worker. In any case an id is now returned too, so that one can match spawn() returns and async and results.

( dbj.log() is my logging function. ) On executing the above testing code , the resulting log is this :

Async started: { done: false, retval: null, id: 120213162 }
Async finished: { done: true, retval: 1,2,3, id: 120213162 }

First line was printed immediately after spawn() returned. And the second line, from inside callback which was assigned to be called when w1(a,b,c) finishes.

I think, by now this AsyncResult mechanism may be even labelled as “useful” ?

Currently I plan to check if there is something somewhere. that I have overlooked. Maybe the whole code can be made simpler, more robust etc.
Also AsyncResult.prototype.toString() returns pitiful JSON string. Which must be made right.