:surfer: Asynchronous flow control with a functional taste to it
:surfer: Asynchronous flow control with a functional taste to it
![contra.png][logo]
Asynchronous flow control with a functional taste to it
λ aims to stay small and simple, while powerful. Inspired by [async][1] and [lodash][2]. Methods are implemented individually and not as part of a whole. That design helps when considering to export functions individually. If you need all the methods in async, then stick with it. Otherwise, you might want to check λ out!
Feature requests will be considered on a case-by-case basis.
Flow Control
Functional
Uncategorized
Install using npm or bower. Or get the [source code][3] and embed that in a `
The only reason `contra` isn't published as `λ` directly is to make it easier for you to type.
[_Back to top_](#quick-links)
# API
These are the asynchronous flow control methods provided by `λ`.
## `λ.waterfall(tasks, done?)`
Executes tasks in series. Each step receives the arguments from the previous step.
- `tasks` Array of functions with the `(...results, next)` signature
- `done` Optional function with the `(err, ...results)` signature
```js
λ.waterfall([
function (next) {
next(null, 'params for', 'next', 'step');
},
function (a, b, c, next) {
console.log(b);
// [_Back to top_](#quick-links)
## `λ.concurrent(tasks, cap?, done?)`
Executes tasks concurrently. Results get passed as an array or hash to an optional `done` callback. Task order is preserved in results. You can set a concurrency cap, and it's uncapped by default.
- `tasks` Collection of functions with the `(cb)` signature. Can be an array or an object
- `cap` Optional concurrency level, used by the internal [queue](#%CE%BBqueueworker-cap1)
- `done` Optional function with the `(err, results)` signature
…
js
λ.series([
function (next) {
setTimeout(function () {
next(null, 'boom');
}, 1000);
},
function (next) {
next(null, 'foo');
}
], function (err, results) {
console.log(results);
// [_Back to top_](#quick-links)
## `λ.each(items, cap?, iterator, done?)`
Applies an iterator to each element in the collection concurrently.
- `items` Collection of items. Can be an array or an object
- `cap` Optional concurrency level, used by the internal [queue](#%CE%BBqueueworker-cap1)
- `iterator(item, key?, cb)` Function to execute on each item
- `item` The current item
- `key` Optional, array/object key of the current item
- `cb` Needs to be called when processing for current item is done
- `done` Optional function with the `(err)` signature
…
js
λ.map({ thing: 900, another: 23 }, function (item, cb) {
setTimeout(function () {
cb(null, item * 2);
}, item);
}, function (err, results) {
console.log(results);
[_Back to top_](#quick-links)
## `λ.map.series(items, iterator, done?)`
Effectively an alias for `λ.map(items, 1, iterator, done?)`.
[_Back to top_](#quick-links)
## `λ.filter(items, cap?, iterator, done?)`
Applies an iterator to each element in the collection concurrently. Produces an object with the filtered results. Task order is preserved in results.
- `items` Collection of items. Can be an array or an object
- `cap` Optional concurrency level, used by the internal [queue](#%CE%BBqueueworker-cap1)
- `iterator(item, key?, cb)` Function to execute on each item
- `item` The current item
- `key` Optional, array/object key of the current item
- `cb` Needs to be called when processing for current item is done
- `err` An optional error which will short-circuit the filtering process, calling `done`
- `keep` Truthy will keep the item. Falsy will remove it in the results
- `done` Optional function with the `(err, results)` signature
…
js
var q = λ.queue(worker);
function worker (job, done) {
console.log(job);
done(null);
}
q.push('job', function () {
console.log('this job is done!');
});
q.push(['some', 'more'], function () {
console.log('one of these jobs is done!');
});
q.on('drain', function () {
console.log('all done!');
// if you enqueue more tasks now, then drain
// will fire again when pending.length reaches 0
});
// [_Back to top_](#quick-links)
## `λ.emitter(thing={}, options={})`
Augments `thing` with the event emitter methods listed below. If `thing` isn't provided, an event emitter is created for you. Emitter methods return the `thing` for chaining.
- `thing` Optional. Writable JavaScript object
- `emit(type, ...arguments)` Emits an event of type `type`, passing any `...arguments`
- `emitterSnapshot(type)` Returns a function you can call, passing any `...arguments`
- `on(type, fn)` Registers an event listener `fn` for `type` events
- `once(type, fn)` Same as `on`, but the listener is discarded after one callback
- `off(type, fn)` Unregisters an event listener `fn` from `type` events
- `off(type)` Unregisters all event listeners from `type` events
- `off()` Unregisters all event listeners
The `emitterSnapshot(type)` method lets you remove all event listeners before emitting an event that might add more event listeners which shouldn't be removed. In the example below, `thing` removes all events and then emits a `'destroy'` event, resulting in a `'create'` event handler being attached. If we just used `thing.off()` after emitting the destroy event, the `'create'` event handler would be wiped out too _(or the consumer would have to know implementation details as to avoid this issue)_.
```js
var thing = λ.emitter();
thing.on('foo', foo);
thing.on('bar', bar);
thing.on('destroy', function () {
thing.on('create', reinitialize);
});
var destroy = thing.emitterSnapshot('destroy');
thing.off();
destroy();The emitter can be configured with the following options, too.
async Debounce listeners asynchronously. By default they're executed in sequence.throws Throw an exception if an error event is emitted and no listeners are defined. Defaults to true.var thing = λ.emitter(); // also, λ.emitter({ foo: 'bar' })
thing.once('something', function (level) {
console.log('something FIRST TROLL');
});
thing.on('something', function (level) {
console.log('something level ' + level);
});
thing.emit('something', 4);
thing.emit('something', 5);
// [_Back to top_](#quick-links)
## `λ.curry(fn, ...arguments)`
Returns a function bound with some arguments and a `next` callback.
```js
λ.curry(fn, 1, 3, 5);
// [_Back to top_](#quick-links)
# Comparison with `async`
[`async`][1]|`λ`
---|---
Aimed at Noders|Tailored for browsers
Arrays for [some][5], collections for [others][6]|Collections for **everyone**!
`apply`|`curry`
`parallel`|`concurrent`
`parallelLimit`|`concurrent`
`mapSeries`|`map.series`
More _comprehensive_|More _focused_
`~29.6k (minified, uncompressed)`|`~2.7k (minified, uncompressed)`
`λ` isn't meant to be a replacement for `async`. It aims to provide a more focused library, and a bit more consistency.
[_Back to top_](#quick-links)
# Browser Support
If you need support for one of the legacy browsers listed below, you'll need `contra.shim.js`.
- IE [_Back to top_](#quick-links)
# License
MIT
[_Back to top_](#quick-links)
[logo]: https://raw.github.com/bevacqua/contra/master/resources/contra.png
[1]: https://github.com/caolan/async
[2]: https://github.com/lodash/lodash
[3]: https://github.com/bevacqua/contra/tree/master/src/contra.js
[4]: https://github.com/bevacqua
[5]: https://github.com/caolan/async#maparr-iterator-callback
[6]: https://github.com/caolan/async#paralleltasks-callbackNo open issues yet, or sync has not completed.