- ×
Asynchronous flow control with a functional taste to it
Filed under application tools › utilitiesShow AllAsynchronous flow control with a functional taste to it
λ
aims to stay small and simple, while powerful. Inspired by async and lodash. 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 inasync
, then stick with it. Otherwise, you might want to checkλ
out!Feature requests will be considered on a case-by-case basis.
Quick Links
API
Flow Control
Functional
Uncategorized
Install
Install using
npm
orbower
. Or get the source code and embed that in a<script>
tag.npm i contra --save
bower i contra --save
You can use it as a Common.JS module, or embed it directly in your HTML.
var λ = require('contra');
<script src='contra.js'></script> <script> var λ = contra; </script>
The only reason
contra
isn't published asλ
directly is to make it easier for you to type.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)
signaturedone
Optional function with the(err, ...results)
signature
λ.waterfall([ function (next) { next(null, 'params for', 'next', 'step'); }, function (a, b, c, next) { console.log(b); // <- 'next' next(null, 'ok', 'done'); } ], function (err, ok, result) { console.log(result); // <- 'done' });
λ.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 objectcap
Optional concurrency level, used by the internal queuedone
Optional function with the(err, results)
signature
λ.concurrent([ function (cb) { setTimeout(function () { cb(null, 'boom'); }, 1000); }, function (cb) { cb(null, 'foo'); } ], function (err, results) { console.log(results); // <- ['boom', 'foo'] });
Using objects
λ.concurrent({ first: function (cb) { setTimeout(function () { cb(null, 'boom'); }, 1000); }, second: function (cb) { cb(null, 'foo'); } }, function (err, results) { console.log(results); // <- { first: 'boom', second: 'foo' } });
λ.series(tasks, done?)
Effectively an alias for
λ.concurrent(tasks, 1, done?)
.Executes tasks in series.
done
gets all the results. Results get passed as an array or hash to an optionaldone
callback. Task order is preserved in results.tasks
Collection of functions with the(next)
signature. Can be an array or an objectdone
Optional function with the(err, results)
signature
λ.series([ function (next) { setTimeout(function () { next(null, 'boom'); }, 1000); }, function (next) { next(null, 'foo'); } ], function (err, results) { console.log(results); // <- ['boom', 'foo'] });
Using objects
λ.series({ first: function (next) { setTimeout(function () { next(null, 'boom'); }, 1000); }, second: function (next) { next(null, 'foo'); } }, function (err, results) { console.log(results); // <- { first: 'boom', second: 'foo' } });
λ.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 objectcap
Optional concurrency level, used by the internal queueiterator(item, key?, cb)
Function to execute on each itemitem
The current itemkey
Optional, array/object key of the current itemcb
Needs to be called when processing for current item is done
done
Optional function with the(err)
signature
λ.each({ thing: 900, another: 23 }, function (item, cb) { setTimeout(function () { console.log(item); cb(); }, item); }); // <- 23 // <- 900
λ.each.series(items, iterator, done?)
Effectively an alias for
λ.each(items, 1, iterator, done?)
.λ.map(items, cap?, iterator, done?)
Applies an iterator to each element in the collection concurrently. Produces an object with the transformation results. Task order is preserved in the results.
items
Collection of items. Can be an array or an objectcap
Optional concurrency level, used by the internal queueiterator(item, key?, cb)
Function to execute on each itemitem
The current itemkey
Optional, array/object key of the current itemcb
Needs to be called when processing for current item is done
done
Optional function with the(err, results)
signature
λ.map({ thing: 900, another: 23 }, function (item, cb) { setTimeout(function () { cb(null, item * 2); }, item); }, function (err, results) { console.log(results); <- { thing: 1800, another: 46 } });
λ.map.series(items, iterator, done?)
Effectively an alias for
λ.map(items, 1, iterator, done?)
.λ.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 objectcap
Optional concurrency level, used by the internal queueiterator(item, key?, cb)
Function to execute on each itemitem
The current itemkey
Optional, array/object key of the current itemcb
Needs to be called when processing for current item is doneerr
An optional error which will short-circuit the filtering process, callingdone
keep
Truthy will keep the item. Falsy will remove it in the results
done
Optional function with the(err, results)
signature
λ.filter({ thing: 900, another: 23, foo: 69 }, function (item, cb) { setTimeout(function () { cb(null, item % 23 === 0); }, item); }, function (err, results) { console.log(results); <- { another: 23, foo: 69 } });
λ.filter.series(items, iterator, done?)
Effectively an alias for
λ.filter(items, 1, iterator, done?)
.λ.queue(worker, cap=1)
Used to create a job queue.
worker(job, done)
Function to process jobs in the queuejob
The current jobdone
Needs to be called when processing for current job is done
cap
Optional concurrency level, defaults to1
(serial)
Returns a queue you can
push
orunshift
jobs to. You can pause and resume the queue by hand.push(job, done?)
Array of jobs or an individual job object. Enqueue those jobs, continue processing (unless paused). Optional callback to run when each job is completedunshift(job, done?)
Array of jobs or an individual job object. Add jobs to the top of the queue, continue processing (unless paused). Optional callback to run when each job is completedpending
Property. Jobs that haven't started processing yetlength
Short-hand forpending.length
, only works if getters can be definedpause()
Stop processing jobs. Those already being processed will run to completionresume()
Start processing jobs again, after apause()
on('drain', fn)
Executefn
whenever there's no more pending (or running) jobs and processing is requested. Processing can be requested usingresume
,push
, orunshift
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 }); // <- 'this job is done!' // <- 'one of these jobs is done!' // <- 'one of these jobs is done!' // <- 'all done!'
λ.emitter(thing={}, options={})
Augments
thing
with the event emitter methods listed below. Ifthing
isn't provided, an event emitter is created for you. Emitter methods return thething
for chaining.thing
Optional. Writable JavaScript objectemit(type, ...arguments)
Emits an event of typetype
, passing any...arguments
emitterSnapshot(type)
Returns a function you can call, passing any...arguments
on(type, fn)
Registers an event listenerfn
fortype
eventsonce(type, fn)
Same ason
, but the listener is discarded after one callbackoff(type, fn)
Unregisters an event listenerfn
fromtype
eventsoff(type)
Unregisters all event listeners fromtype
eventsoff()
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 usedthing.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).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 anerror
event is emitted and no listeners are defined. Defaults totrue
.
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); // <- 'something FIRST TROLL' // <- 'something level 4' // <- 'something level 5'
Returns
thing
.Events of type
error
have a special behavior.λ.emitter
will throw if there are noerror
listeners when an error event is emitted. This behavior can be turned off settingthrows: false
in the options.var thing = { foo: 'bar' }; λ.emitter(thing); thing.emit('error', 'foo'); <- throws 'foo'
If an
'error'
listener is registered, then it'll work just like any other event type.var thing = { foo: 'bar' }; λ.emitter(thing); thing.on('error', function (err) { console.log(err); }); thing.emit('error', 'foo'); <- 'foo'
λ.curry(fn, ...arguments)
Returns a function bound with some arguments and a
next
callback.λ.curry(fn, 1, 3, 5); // <- function (next) { fn(1, 3, 5, next); }
Comparison with
async
async
λ
Aimed at Noders Tailored for browsers Arrays for some, collections for others 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 forasync
. It aims to provide a more focused library, and a bit more consistency.Browser Support
If you need support for one of the legacy browsers listed below, you'll need
contra.shim.js
.- IE < 10
- Safari < 6
- Opera < 16
require('contra/shim'); var λ = require('contra');
<script src='contra.shim.js'></script> <script src='contra.js'></script> <script> var λ = contra; </script>
The shim currently clocks around
~1.2k
minified, uncompressed.License
MIT