• With almost almost all setup type of functions asking for a callback when done, such as connect(), Tasker is a helpful tool to fire off what ever (asynchronous) tasks that have to complete successfully before moving on or - on completion with error(s) - take other actions.

    It is related to contributions made by @Alex in conversation about Javascript Promises?
    and [EDIT] @JumJum in conversation about Async handling.

    Taskser's main built-in features are:

    • supports ok and err or callbacks
    • supports retries
    • keeps statistics about successes / failures and (re)tries
    • furnishes retries
    • provides task with single tasker callback
    • provides task with try count
    • provides statistics, to ok and err callbacks
    • provides means for easy, complete start over
    • allows application defined names for task callback and try count
    • tasks are invoked with setTimeout() to avoid calling stack fill-up on retries of 'synchronous' / chained tasks.
    • supports the next() concept with nesting / chaining

    Initially, I had even a fatter version supporting (optional) extended logging, names for Tasker instances, names for the tasks, additional statistics about start time, end time, execution/elapsed time, and task results with passing them to the ok and err callbacks.

    The fat version included also a part callback function invoked on successful or failed completion of each individual task to take additional action.

    Dropping tries information, logging, and passing these things to the callbacks makes this implementation even lighter.

    I'm using it as a module for simplifying synchronization of my setup tasks. Use is though not limited to just that. Anywhere in the app where a set of things have to happen before process flow can continue, a new Tasker can be instantiated. Taskers are fully reentrant and can be nested/cascaded/chained...

    Setup of tasks can be inline in the Tasker constructor as anonymous functions or upfront as globally or locally scoped variables.

    Skeletal task definition looks like this:
    *Note: trie is for reserved word try ;-)*

    var taskX = function(done,trie) {
      // do things...
      // on success (in success callback):
      done(true);
      // on error (in failure callback):
      done(false); // for no retries
      done(false,3) // with 2 retries - totally 3 tries
    }; 
    

    For the ok and err setup see next post with example of 5 tasks.

    Invocation of the Tasker looks like this:

    Tasker.new([task0Fnct,task1Fnct,task2Fnct,...],okFnct,errFnct,lg);
    

    *Tasker code (with some doc):

    // Tasker - kind of a 'Purposed' Promise
    
    // allows retries, resumes when all task are completed with
    // either ok or error function depending on the tasks results
    
    // Helpful for sequence agnostic setup of multiple interdependent 
    // 'things' that require resume callbacks, for example:
    
    // Setup of multiple communication devices, display, GPS, etc.
    // When all successfully setup and ready, the application code
    // as placed in/passed as the ok() function will resume.
    
    // Task is a function that gets passed a done function and a try cnt.
    // On successfull completion, task calls done with true (in callback).
    // On failure, it calls done with false and optional number of tries.
    // ok and err functions get number of successfully passed tasks (oks)
    // and arrays of statutes (sts, true/false), actual tries, and tasks.
    
    // Tasker is invoked with array of tasks, ok and err function (and
    // optional boolean for logging:
    
    // Tasker.new([t0Fnct,t1Fnct,t2Fnct,...],okFnct,errFnct,lg);
    
    // Tasker can be made fatter/leaner by adding statistics about
    // start, end, and execution times / removing log, oks, and tries
    
    var Tasker = (function(){
      var T = function(tasks,ok,err,lg) {
        this.tasks = tasks; 
        this.ok = (ok) ? ok : function(){};
        this.err = (err) ? err : function(){};
        this.cnt = 0; this.sts = []; this.tries = []; this.lg = lg;
        tasks.forEach(function(t,id){ this._do(this,t,id,1); },this);
      };
      T.prototype._do = function(_this,t,id,n) {
        if (this.lg) console.log("Task "+id+" kickoff "+n);
        var done = function(ok,tries){ _this.done(ok,id,n,tries); };
        this.tries[id] = n; setTimeout(function(){ t(done,n); },1); 
      },
      T.prototype.done = function(ok,id,n,tries) {
        if (this.lg) console.log("Task "+id+" try "+n+" ok: "+ok);
        this.cnt++; if (!(this.sts[id] = ok) && tries && (tries > n)) { 
          this.cnt--; this._do(this,this.tasks[id],id,n + 1); }
        if (this.cnt === this.tasks.length) {
          var oks = this.sts.filter(function(o){ return o; }).length;
          var sts = this.sts, _tries = this.tries, _tasks = this.tasks;
          this.sts = null; this.tries = null; this.tasks = null;
          this[(oks == this.cnt) ? "ok" : "err"](oks,sts,tries,tasks); 
        }
      };
      return T;
    })();
    

    *EDIT* (at the time of version 1v94 (2017-08-29))

    Feel free to continue reading in this conversation about Tasker... it will make you just more appreciate what happened here:

    Version 1v86 (2016-07-05) introduced Promise and Promise has matured thru version 1v91 (2017-01-12). Promise makes life of synchronizing/sequencing of asynchronous tasks/callback of callbacks of callbacks of... much much easier... Promise is practically the only way out of callback-hell.

About

Avatar for allObjects @allObjects started