lasso

Asynchronous control flow library for JavaScript.

npm install lasso
2 downloads in the last week
4 downloads in the last month

lasso.js

Overview

lasso.js is an asynchronous control flow library for JavaScript (which, of course, also works with synchronous code). Asynchronous functions can be called in sequence or in parallel and errors are automatically caught and handed to a callback function which you specify.

Setup

The same lasso.js file works in CommonJS environments (like node.js), AMD environments (like RequireJS), and plain old browser environments without any loaders. Consider the following examples:

Node.js

Install lasso.js with npm install lasso and then require the module:

var lasso = require('lasso');
// use `lasso` here

AMD

Place lasso.js within your application's directory structure and require or define as usual:

require(['path/to/lasso'], function (lasso) {
  // use `lasso` here
});

Plain Browser

Include lasso.js in your page by using a standard script tag:

<script src="path/to/lasso.js"></script>
<script>
  // use `lasso` here
</script>

Example Usage

Running Code Sequentially

Consider the following:

lasso.seq(function (next) {
  setTimeout(function () {
    next(10);
  }, 1000);
}, function (val, next) {
  setTimeout(function () {
    next(10 * val, 'Hello, World!');
  }, 1000);
}, function (err, num, str) {
  console.log(num); // Logs `100`
  console.log(str); // Logs `Hello, World!`
});

In this example the first function will run and pass 10 to the next function which passes 100 and Hello, World! to the final function. You can have as many functions as you want and pass as many values between each function as you need. All functions will receive a callback (next, in this example) as its last argument. The callback function is used to pass arguments to the next function. The only function which doesn't receive a callback function is the last function which will have any thrown error as its first argument followed by any arguments passed by the previous function.

Now consider the following example:

lasso.seq(function (next) {
  // Do something but don't pass anything to the next function.
  next();
}, function (next) {
  throw new Error('This is intentional.');
  next(); // This is never called as an error was thrown.
}, function (next) {
  // We never reach this point
  next();
}, function (err) {
  if (err) {
    console.log(err.message); // Logs `This is intentional.`
  }
});

As you can see the second function throws an error and execution immediately goes to the final function with its first argument being the thrown error. If an error is thrown, then err will be defined and all other arguments for the final function will be undefined.

Running Code in Parallel

Consider the following example:

lasso.par(function (done) {
  setTimeout(function () {
    done('Hello');
  }, 1000);
}, function (done) {
  setTimeout(function () {
    done('World');
  }, 500);
}, function (errs, greeting, name) {
  console.log('%s, %s!', greeting, name); // Logs `Hello, World!`
});

Unlike in running code sequentially, functions running in parallel do not actually pass information between each other. Data is only passed to the final function and only after each previous function has either called its callback or thrown an error. In this example the second function will finish before the first function, but the final function will only be called after both previous functions are finished.

Like in running sequentially, you can throw errors. Unlike in running code sequentially, the final function will only be called once every previous function has finished. Consider the following example:

lasso.par(function (done) {
  throw new Error('Error 1');
  done('Value 1');
}, function (done) {
  done('Value 2');
}, function (done) {
  throw new Error('Error 3');
  done('Value 3');
}, function (errs, val1, val2, val3) {
  console.log('First: %s', val1 || errs[0].message); // Logs `First: Error 1`
  console.log('Second: %s', val2 || errs[1].message); // Logs `Second: Value 2`
  console.log('Third: %s', val3 || errs[2].message); // Logs `Third: Error 2`
});

If there are any errors then the first argument of the final function will be an array of those errors with each error indexed in the proper location according to the order in which the functions were declared. If there are no errors, then the first argument of the final function will be false. Following the errors array will be the value that each function passed to its callback function in the order the functions were declared. It is important to note that unlike in running code sequentially, each function's callback function only takes one argument. If you need to pass more data to the final function then you should either use an object or an array as your argument.

Running code in parallel also supports an alternate syntax:

lasso.par(function (done) {
  throw new Error('Error 1');
  done('Value 1');
}, function (done) {
  done('Value 2');
}, function (done) {
  throw new Error('Error 3');
  done('Value 3');
}, function (err1, v1, err2, v2, err3, v3) {
  console.log(v1 || err1.message); // Logs `Error 1`
  console.log(v2 || err2.message); // Logs `Value 2`
  console.log(v3 || err3.message); // Logs `Error 3`
});

In this example we have three functions which execute in parallel and then a final function which takes six arguments. These arguments will follow the format of err1, val1, err2, val2, ..., errn, valn. If any error is defined, then its corresponding value is undefined and vice-versa.

Running the Tests

To run the tests first you must install mocha globally using npm install -g mocha. Once mocha is installed you can either run (from this directory) npm test or mocha test to run the tests.

License

The MIT License

Copyright (c) 2012 Kenneth Powers

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

npm loves you