Skip to content

Instantly share code, notes, and snippets.

@MiguelCastillo
Last active August 29, 2015 14:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MiguelCastillo/ed4455f99fbd9931c964 to your computer and use it in GitHub Desktop.
Save MiguelCastillo/ed4455f99fbd9931c964 to your computer and use it in GitHub Desktop.
Sample task manager to handle recursion with trampoline
/**
* Task manager to handle queuing up async tasks in an optimal manner
*/
var TaskManager = {
_asyncQueue: [],
asyncTask: function(task) {
if (TaskManager._asyncQueue.push(task) === 1) {
async(TaskManager.taskRunner(TaskManager._asyncQueue));
}
},
asyncQueue: function(queue) {
if (queue.length === 1) {
TaskManager.asyncTask(queue[0]);
}
else {
TaskManager.asyncTask(TaskManager.taskRunner(queue));
}
},
taskRunner: function(queue) {
return function runTasks() {
var task;
while ((task = queue[0])) {
TaskManager._runTask(task);
queue.shift();
}
};
},
_runTask: function(task) {
try {
task();
}
catch(ex) {
printDebug(ex);
}
}
};
function printDebug(ex) {
if (Factory.debug) {
console.error(ex);
if (ex && ex.stack) {
console.log(ex.stack);
}
}
}
@MiguelCastillo
Copy link
Author

Task manager used in spromise to manage recursion as a sudo trampoline implementation. Here are part of the code that use the task manager

  /**
   * Figure out if the promise is pending/resolved/rejected and do the appropriate
   * action with the callback based on that.
   */
  StateManager.prototype.enqueue = function (state, cb) {
    if (!this.state) {
      (this.queue || (this.queue = [])).push(TaskAction);
    }
    else {
      // If the promise has already been resolved and its queue has been processed, then
      // we need to schedule the new task for processing ASAP by putting in the asyncQueue
      TaskManager.asyncTask(TaskAction);
    }

    var stateManager = this;
    function TaskAction() {
      if (stateManager.state === state || states.always === state) {
        cb.apply(stateManager.context, stateManager.value);
      }
      else if (states.notify === state) {
        cb.call(stateManager.context, stateManager.state, stateManager.value);
      }
    }
  };

  /**
   * Transitions the state of the promise from pending to either resolved or
   * rejected.  If the promise has already been resolved or rejected, then
   * this is a noop.
   */
  StateManager.prototype.transition = function (state, value, context) {
    if (this.state) {
      return;
    }

    this.state   = state;
    this.context = context;
    this.value   = value;

    var queue = this.queue;
    if (queue) {
      this.queue = null;
      TaskManager.asyncQueue(queue);
    }
  };

@vnadoda
Copy link

vnadoda commented Dec 24, 2014

Miguel,
Just curious, does TaskAction need to be constructor function?

@MiguelCastillo
Copy link
Author

@vnadoda Not at all. It can also be function expressions. In my particular example it is a function declaration so that I can define it at the bottom of the containing method to make the code a bit cleaner for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment