Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Simple Atomic Task Definition

Fetching latest commit…

Octocat-spinner-32-eaf2f5

Cannot retrieve the latest commit at this time

Octocat-spinner-32 examples
Octocat-spinner-32 lib
Octocat-spinner-32 src
Octocat-spinner-32 test
Octocat-spinner-32 .gitignore
Octocat-spinner-32 .travis.yml
Octocat-spinner-32 README.md
Octocat-spinner-32 index.js
Octocat-spinner-32 package.json
Octocat-spinner-32 taskify.js
README.md

Taskify

This is a simple task execution helper that is heavily influenced from jake and grunt. It's kind of like jake but without the build goodies, and designed to work in the browser as well as node.

Build Status

Example Usage

Define a task a:

taskify('a', function() {
    console.log('a'); 
});

Then define another task that relies on task a:

taskify('b', ['a'], function() {
    console.log('b'); 
});

Run task b:

taskify.run('b');

Which would generate the following output:

a
b

Asynchronous Behaviour

Specifying that a task handler behaves asynchronously is very similar to the way you would do this in a grunt task:

taskify('c', function() {
    // call the async method of the task (passed to the runner as this)
    var done = this.async(); 

    // when the task has been completed call done
    // the first argument is reserved for an error (if one occured)
    // and subsequent arguments will be placed on the context.results object
    setTimeout(function() {
        done();
    }, 1000);
});

Or a slightly less contrived example:

taskify('load-data', function() {
    fs.readFile(path.resolve('data.txt'), 'utf8', this.async()); 
});

Capturing Result Data

When you call the taskify.run function, Taskify creates a new ExecutionContext for the task dependency tree that will be executed. This execution context is not persistent though and only lasts until the requested tasks have completed their execution (or you capture the reference).

To capture the results of a task execution you will need to handle the complete event for a particular task. Let's look at the simple example of our load-data task from before:

taskify.run('load-data').on('complete', function(err) {
    if (err) return;

    console.log('loaded data: '  + this.context.results['load-data']); 
});

Additionally, because Taskify uses eve under the hood for eventing, you can implement eve handlers to capture the complete events also:

eve.on('taskify.complete.load-data', function(err) {
    if (err) return;

    console.log('loaded data: '  + this.context.results['load-data']); 
});

Argument Passing

When running a task using the taskify.run function (or by running the bound function returned from a taskify.select) call, you can supply arguments that will be passed to that task handler and all precondition tasks.

As an example, let's pass console.log as a task handler:

taskify('log', console.log);

And then run the task passing through the message arguments:

taskify.run('log', 'Hi there', { test: true });

This would generate the following output:

Hi there { test: true }

Experimental Use Case: Handling HTTP Requests without Middleware

While this was not one of the reasons I created Taskify, it is something I experimented with as a way of resolving preconditions for a particular route handler. While most web frameworks implement middleware to handle things like cookie or body parsing Taskify can offer an alternative approach.

For instance, consider the following example implementing using Tako. The example defines an auth task that can be specified as a precondition for a task that would require user awareness.

The great thing here is that the execution path for a simple request handler does not need to be passed through unnecessary middleware, but only through tasks that have been specifically defined as preconditions (or preconditions of preconditions) of the route handler.

var tako = require('tako'),
    taskify = require('taskify'),
    app = tako(),
    knownUsers = {
        DamonOehlman: {
            name: 'Damon Oehlman',
            twitterHandle: 'DamonOehlman'
        }
    };

// define the authenticator task
taskify('auth', function(req, res) {
    // inspect the req headers
    var userId = req.headers['x-user-id'];

    // check that the user is within the list of know 
    if (! knownUsers[userId]) return new Error('A known user is required');

    // add the user to the context
    this.context.user = knownUsers[userId];
});

// define a task that tells us the twitter handle of the user
taskify('writeHandle', ['auth'], function(req, res) {
    res.end(this.context.user.twitterHandle);
});

// define a task that says hi
taskify('sayHi', function(req, res) {
    res.end('hi');
});

taskify('reportError', function(req, res) {
    res.end('error: ' + this.context.errors[0].message);
});

// set the default fallback
taskify.defaults({
    fallback: 'reportError'
});

// wire up the application routes
app.route('/hi', taskify.select('sayHi'));
app.route('/handle', taskify.select('writeHandle'));

// start the server
app.httpServer.listen(3000);

Something to note is that the above example makes use of the taskify.select function which returns a function reference that can be used to execute the task. The arguments passed to this function reference are then passed through to all the task runners. In this way it is fairly simple to use Taskify to handle http requests using most lightweight node web frameworks.

Something went wrong with that request. Please try again.