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 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
// // 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()
:
1 2 3 4 5 6 7 8 9 10 11 |
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 :
1 2 |
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.