code: function Task(runCb, thisArg) {
      if (runCb !== undefined && thisArg === undefined)
        throw new Error('Almost certainly, you meant to pass a thisArg.');
      this.runCb_ = runCb;
      this.thisArg_ = thisArg;
      this.afterTask_ = undefined;
      this.subTasks_ = [];
    }
docs: A task is a combination of a run callback, a set of subtasks, and an after
  task.
  
  When executed, a task does the following things:
  1. Runs its callback
  2. Runs its subtasks
  3. Runs its after callback.
  
  The list of subtasks and after task can be mutated inside step #1 but as
  soon as the task's callback returns, the subtask list and after task is
  fixed and cannot be changed again.
  
  Use task.after().after().after() to describe the toplevel passes that make
  up your computation. Then, use subTasks to add detail to each subtask as it
  runs. For example:
  var pieces = [];
  taskA = new Task(function() { pieces = getPieces(); });
  taskA.after(function(taskA) {
  pieces.forEach(function(piece) {
  taskA.subTask(function(taskB) { piece.process(); }, this);
  });
  });
  
  @constructor