npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

lib-task

v2.0.0

Published

JavaScript library for building and running tasks.

Downloads

8

Readme

task.js

npm version Travis CI Lincense MIT

task.js is a JavaScript library for creating logical groups of instructions called tasks. These tasks leverage the Promise pattern to allow application logic to specify when a task is done(result) or failed(reason).

Advantages over direct Promises

  • You don't have to promisify your async functions that use callbacks.
  • However, you can safely use Promises within tasks.
  • Powerful APIs to execute a group of tasks, or the same task a number of times.
  • You can give a human readable name to your tasks thereby improving code readability.
  • These tasks can be easily testable with Promise based frameworks like mocha.js.

Installation

  • For Node.js or browserify/webpack projects

    npm install lib-task
    var Task = require('lib-task');
  • For standard web projects

    git clone https://github.com/manjeshbhargav/task.js.git
    cd task.js && npm run build

    Then, you can use ./dist/task.js or ./dist/task.min.js in your web project using <script>.

Task template

A template is basically a function that defines the set of instructions that the task will be performing. It follows this format:

/**
 * A task template.
 * @param {...*} taskArguments - Arguments for executing the task.
 * @param {function} done - Called (with results, if any) by the task when it's done.
 * @param {function} failed - Called (with errors, if any) by the task when it fails.
 * @returns {*}
 */
function template(...taskArguments, done, failed) {
  ...
  ...
  doSomeAsyncTask(args, done, failed);
}

Creating a task

You can create a task like this:

var loginAttempt = Task.create('attempting to log in', function(endpoint, credentials, done, failed) {
  var username = credentials.username;
  var password = credentials.password;
  // Using JQuery AJAX to contact the login endpoint
  $.post({
    url: endpoint,
    data: { u: username, p: password },
    success: function(response) { done(JSON.parse(response)); },
    failure: failed
  });
});

Here, endpoint and credentials are the arguments required for doing the task. In this example, done() is called when the login endpoint responds with a success JSON message, and failed() is called when it responds with the reason for the failure.

There are other ways to specify when the task is done/failed:

  • returning a value: A task is considered done if the template returns any non-Promise value, and failed if it throws an exception.

    var addTask = Task.create('add two numbers', function(a, b) {
      return (a + b);
    });
  • returning a Promise: A task is considered done/failed if the Promise returned by the template is resolved/rejected.

    var promiseTask = Task.create('track a promise', function(a, b) {
      ...
      ...
      return someAsyncFunctionThatReturnsAPromise(a, b);
    });

Executing a task

The loginAttempt task that was created in the previous section can be executed like this:

loginAttempt.do('/services/login', {
  usename: 'johndoe',
  password: 'xyz123'
}).then(function(success) {
  console.log('Login successful! - ', success);
}).catch(function(error) {
  console.error('Login failed! - ', error);
});

Here, the argument passed to done() is passed on to the Promise's then() callback, while the argument passed to failed() is passed on to the catch() callback.

  • addTask from the previous section can be executed like this:

    addTask.do(2, 3).then(function(sum) {
      // sum is the return value of addTask's template.
      console.log('Sum is - ', sum);
    }).catch(function(e) {
      console.error('Exception thrown while executing template - ', e); 
    });
  • promiseTask from the previous section can be executed like this:

    promiseTask.do('a', 'b').then(function(result) {
      console.log('Promise returned by the template was resolved with - ', result);
    }).catch(function(error) {
      console.error('Promise returned by the template was rejected with - ', error);
    });

Canceling a task

Sometimes we need to cancel a task after starting it. We can do it like this:

var timeout = null;
var task = Task.create('cancelable task', function(ms, done, failed) {
  timeout = setTimeout(function() { failed('Timeout over!'); }, ms);
});

task.do(5000).then(function() {...}).catch(function(reason) {
  if (reason === 'canceled') {
    console.log('We are here because the task was actively canceled.');
  }
  else {
    console.log('We are here because the task failed().');
  }
  clearTimeout(timeout);
  timeout = null;
});

// The argument to cancel() is anything that we want to
// pass to the Promise's catch() that helps us determine why it
// was rejected.
task.cancel('canceled');

Timing out a task

Sometimes we want to set a time limit for a task to complete (done() or failed()). We can do it like this:

var xhr = new XMLHttpRequest();
var getUrl = Task.create('get content of url', function(url, done, failed) {
  xhr.open('GET', url, true);
  xhr.onreadystatechange = function() {
    if (xhr.status === 200 && xhr.readyState === 4) {
      done(xhr.responseText);
    }
  };
  xhr.send();
});

// The second argument to timeout() is anything that we want to
// pass to the Promise's catch() that helps us determine why it
// was rejected.
getUrl.timeout(5000, { reason: 'timeout' });

getUrl.do('http://www.x.y.com/?a=b').then(function(response) {
  console.log('Response: ', response);
}).catch(function(error) {
  if (error.reason === 'timeout') {
    console.log('Task timed out.');
  }
  xhr.abort();
});

Executing tasks serially

Sometimes we need to perform a set of tasks serially, where the next task depends on the result from the previous task. We can do it like this:

var task1 = Task.create('task 1', function(task1Arg, done, failed) {...});
var task2 = Task.create('task 2', function(task1Result, done, failed) {...});
var task3 = Task.create('task 3', function(task2Result, done, failed) {...});
var taskSequence = Task.sequence('sequence', [task1, task2, task3]);

// The arguments of Task#do() are arguments for the first task in the sequence.
taskSequence.do(10).then(function(task3Result) {
  console.log('All done one after the other!');
}).catch(function(error) {
  console.error('One of the tasks failed - ', error);
});

Executing tasks in parallel

Sometimes we need to wait for a set of independent tasks to be executed before we can proceed. We can do it like this:

var task1 = Task.create('task1', function(arg1, done, failed) {...});
var task2 = Task.create('task2', function(arg21, arg22, done, failed) {...});
var task3 = Task.create('task3', function(arg31, done, failed) {...});
var taskParallel = Task.parallel('parallel', [task1, task2, task3]);

// The arguments for Task#do() is (args1, args2, args3), where:
// * args1 => Array of arguments for task1's template
// * args2 => Array of arguments for task2's template
// * args3 => Array of arguments for task3's template
// NOTE: If there is only one argument for a task, then there is no
//       need to enclose it in an array.
taskParallel.do(1, ['2', true], {}).then(function(results) {
  console.log('Results of all completed tasks - ', results);
}).catch(function(error) {
  console.error('One of the tasks failed - ', error);
});

Executing an anonymous task

Sometimes we don't want to create and then do a task because it is one-off and we don't intend to re-do it at any point in the future. We can do it like this:

Task.do(function(a, b, done, failed) {
  startMyApplication(a, b, function(started, result) {
    var status = started ? done : failed;
    status(result);
  });
}, 1, '2').then(function(outcome) {
  console.log('Application successfully started! - ', outcome);
}).catch(function(error) {
  console.error('Problem starting application! - ', error);
});

Re-trying a task

Sometimes we want to try a task a number of times until it succeeds, or we've tried a certain number of times. Ex: If we lose our connection with the server, we would want to re-try connecting for a certain number of times. We can do it like this:

var numRetries = 10;
var retryConnection = Task.try('retry connecting to server', function(request, done, failed) {
  request.connect('/server/connect', function(response) {
    if (response.connection) { done(response.connection); }
    else { failed(response.error); }
  });
});

function retryConnect() {
  retryConnection.do(new Request(), numRetries).then(function(connection) {
    console.log('Connected! - ', connection);
    connection.on('lost', retryConnect);
  }).catch(function(error) {
    console.error('Failed to connect after ' + numRetries + ' tries! - ', error);
  });
}

Running a task for each item in an array

Sometimes we want to run a task on each item of an array, and once we have gotten all the results, act on them (like Array.prototype.map(), only async). We can do it like this:

var getHtmlMap = Task.map('get html of a given url', function(url, done, failed) {
  http.get(url, function(response) {
    var html = '';
    response.on('data', function(data) {
      html += data;
    });
    response.on('end', function() {
      done(html);
    });
  }).on('error', failed);
});

// The argument for Task#do() is an array where the task has to be
// performed once for each item in parallel.
getHtmlMap.do(['http://www.ex1.com', 'http://www.ex2.com']).then(function(htmls) {
  htmls.forEach(function(html, i) {
    console.log('HTML["' + domains[i] + '"]: ', html);
  });
}).catch(function(error) {
  console.log('Failed to get htmls - ', error);
});

Delayed execution of a task

Sometimes we want to execute a task after a certain period of time. We can do it like this:

var delayedTask = Task.delay('check status after 5 seconds', function(url, done, failed) {
  $.getJSON(url, done, failed);
});

// The last argument to Task#do() is the wait time in milliseconds.
delayedTask.do('http://www.x.y.com/status/me', 5000).then(function(status) {
  console.log('Status: ', status);
}).catch(function(error) {
  console.log('Failed to get status: ', error);
});