Higher-order functions (synchronous and asynchronous each/eachSeries/map/filter/fold) and functions for flow control (parallel/series/waterfall) in under 1 KB.
- API is similar (not identical) to that of the Async library
- 2.5 KB minified, or about 0.9 KB minified and gzipped
- Legible tests, with 100% coverage
Savoy’s higher-order functions differ from Async’s in the following ways:
- The signature of the
fn
iterator is different. Thecb
callback (invoked to signal the end of each iteration offn
) is the first argument offn
. In addition,fn
is also passed the index/key of the current element, and the originalcollection
itself. - If passed is an Object,
map
andfilter
will return an Object. (If passed an Object, Async’smap
andfilter
will return an Array.)
Also, mainly this:
Inventing your own wheels gives you a deep appreciation and understanding of how wheels work and what makes a good one.
In all of the method signatures below, collection
(in each/eachSeries/map/filter/fold) and fns
(in parallel/series/waterfall) can either be an Array or an Object literal.
savoy.each(collection, fn) — synchronous each
savoy.each([1, 2, 3], function(val, i, arr) {
console.log(val, i, arr);
//=> 1, 0, [ 1, 2, 3 ]
//=> 2, 1, [ 1, 2, 3 ]
//=> 3, 2, [ 1, 2, 3 ]
});
-
Break from the loop by explicitly returning
false
fromfn
:savoy.each([1, 2, 3], function(val, i, arr) { console.log(val, i, arr); //=> 1, 0, [ 1, 2, 3 ] //=> 2, 1, [ 1, 2, 3 ] if (i === 1) { return false; } });
savoy.each(collection, fn, done) — asynchronous each
savoy.each({ a: 1, b: 2, c: 3 }, function(cb, val, key, obj) {
console.log(val, key, obj);
//=> 1, 'a', { a: 1, b: 2, c: 3 }
//=> 2, 'b', { a: 1, b: 2, c: 3 }
//=> 3, 'c', { a: 1, b: 2, c: 3 }
cb();
}, function(err) {
console.log(err);
//=> null
});
- The asynchronous function
fn
is called in parallel over each item incollection
. - Invoke the
cb
callback infn
to signal the end of each iteration offn
. - The signature of the
cb
callback iscb(err)
. Iferr
is truthy, thedone
callback is called exactly once with theerr
. - When
fn
has completed execution over every item in thecollection
, thedone
callback is called exactly once with a falsyerr
.
savoy.eachSeries(collection, fn) — synchronous eachSeries
- Alias of
savoy.each
.
savoy.eachSeries(collection, fn, done) — asynchronous eachSeries
savoy.each({ a: 1, b: 2, c: 3 }, function(cb, val, key, obj) {
console.log(val, key, obj);
//=> 1, 'a', { a: 1, b: 2, c: 3 }
//=> 2, 'b', { a: 1, b: 2, c: 3 }
//=> 3, 'c', { a: 1, b: 2, c: 3 }
cb();
}, function(err) {
console.log(err);
//=> null
});
- The asynchronous function
fn
is called in series over each item incollection
. - Invoke the
cb
callback infn
to signal the end of each iteration offn
. - The signature of the
cb
callback iscb(err)
. Iferr
is truthy, we stop iterating over thecollection
, and thedone
callback is called exactly once with theerr
. - When
fn
has completed execution over every item in thecollection
, thedone
callback is called exactly once with a falsyerr
.
savoy.map(collection, fn) — synchronous map
var result = savoy.map({ a: 1, b: 2, c: 3 }, function(val, key, obj) {
console.log(val, key, obj);
//=> 1, 'a', { a: 1, b: 2, c: 3 }
//=> 2, 'b', { a: 1, b: 2, c: 3 }
//=> 3, 'c', { a: 1, b: 2, c: 3 }
return val * 2;
});
console.log(result);
//=> { a: 2, b: 4, c: 6 }
savoy.map(collection, fn, done) — asynchronous map
savoy.map([1, 2, 3], function(cb, val, i, arr) {
console.log(val, i, arr);
//=> 1, 0, [1, 2, 3]
//=> 2, 1, [1, 2, 3]
//=> 3, 2, [1, 2, 3]
cb(null, val * 2);
}, function(err, result) {
console.log(err, result);
//=> null, [2, 4, 6]
});
- The asynchronous function
fn
is called in parallel over each item incollection
. - Invoke the
cb
callback infn
to signal the end of each iteration offn
. The signature of thecb
callback iscb(err, mapVal)
:err
— If truthy, thedone
callback is called exactly once with theerr
.mapVal
— This is accumulated in theresult
argument of thedone
callback.
- When
fn
has completed execution over every item in thecollection
, thedone
callback is called exactly once with a falsyerr
and theresult
of the map. - Note that if
collection
is an Object:result
will also be an Object.- Items in
result
may not be in the same order as their corresponding items in the originalcollection
.
savoy.filter(collection, fn) — synchronous filter
var result = savoy.filter([1, 2, 3], function(val, i, arr) {
console.log(val, i, arr);
//=> 1, 0, [1, 2, 3]
//=> 2, 1, [1, 2, 3]
//=> 3, 2, [1, 2, 3]
return val > 1;
});
console.log(result);
//=> [2, 3]
savoy.filter(collection, fn, done) — asynchronous filter
savoy.filter({ a: 1, b: 2, c: 3 }, function(cb, val, key, obj) {
console.log(val, key, obj);
//=> 1, 'a', { a: 1, b: 2, c: 3 }
//=> 2, 'b', { a: 1, b: 2, c: 3 }
//=> 3, 'c', { a: 1, b: 2, c: 3 }
cb(null, val > 1);
}, function(err, result) {
console.log(err, result);
//=> null, { b: 2, c: 3 }
});
- The asynchronous function
fn
is called in parallel over each item incollection
. - Invoke the
cb
callback infn
to signal the end of each iteration offn
. The signature of thecb
callback iscb(err, predicate)
:err
— If truthy, thedone
callback is called exactly once with theerr
.predicate
— If truthy, the current item is added to theresult
argument of thedone
callback.
- When
fn
has completed execution over every item in thecollection
, thedone
callback is called exactly once with a falsyerr
and theresult
of the filter. - Note that if
collection
is an Object:result
will also be an Object.- Items in
result
may not be in the same relative order as they were incollection
.
savoy.fold(collection, acc, fn) — synchronous fold
var result = savoy.fold({ a: 1, b: 2, c: 3 }, 0, function(acc, val, key, obj) {
console.log(acc, val, key, obj);
//=> 1, 'a', { a: 1, b: 2, c: 3 }
//=> 2, 'b', { a: 1, b: 2, c: 3 }
//=> 3, 'c', { a: 1, b: 2, c: 3 }
return acc + val;
});
console.log(result);
//=> 6
savoy.fold(collection, acc, fn, done) — asynchronous fold
savoy.fold([1, 2, 3], 0, function(cb, acc, val, i, arr) {
console.log(acc, val, i, arr);
//=> 0, 1, 0, [1, 2, 3]
//=> 1, 2, 1, [1, 2, 3]
//=> 3, 3, 2, [1, 2, 3]
cb(null, acc + val);
}, function(err, result) {
console.log(err, result);
//=> null, 6
});
- The asynchronous function
fn
is called in series over each item incollection
. - Invoke the
cb
callback infn
to signal the end of each iteration offn
. The signature of thecb
callback iscb(err, foldVal)
:err
— If truthy, thedone
callback is called exactly once with theerr
.foldVal
— This is the value foracc
that is passed to the next iteration offn
.
- When
fn
has completed execution over every item in thecollection
, thedone
callback is called exactly once with a falsyerr
and theresult
of the fold.
savoy.parallel(fns [, done])
savoy.parallel([
function(cb) {
cb(null, 1);
},
function(cb) {
cb(null, 2);
},
function(cb) {
cb(null, 3);
}
], function(err, result) {
console.log(err, result);
//=> null, [1, 2, 3]
});
- Each function in
fns
is called in parallel. - Invoke the
cb
callback in each function to signal the end of the function. The signature of thecb
callback iscb(err, val)
:err
— If truthy, thedone
callback is called exactly once with theerr
.val
— This is accumulated in theresult
argument of thedone
callback.
- When every function in
fns
has completed execution, thedone
callback is called exactly once with a falsyerr
and theresult
of each function.
savoy.series(fns [, done])
savoy.series({
a: function(cb) {
cb(null, 1);
},
b: function(cb) {
cb(null, 2);
},
c: function(cb) {
cb(null, 3);
}
}, function(err, result) {
console.log(err, result);
//=> null, { a: 1, b: 2, c: 3 }
});
- Each function in
fns
is called in series. - Invoke the
cb
callback in each function to signal the end of the function. The signature of thecb
callback iscb(err, val)
:err
— If truthy, thedone
callback is called exactly once with theerr
.val
— This is accumulated in theresult
argument of thedone
callback.
- When the entire series of functions has completed execution, the
done
callback is called exactly once with a falsyerr
and theresult
of each function.
savoy.waterfall(fns [, done])
savoy.waterfall([
function(cb) {
cb(null, 'a', 'b');
},
function(cb, arg1, arg2) {
console.log(arg1, arg2);
//=> 'a', 'b'
cb(null, 'c');
},
function(cb, arg) {
console.log(arg);
//=> 'c'
cb(null, 'd', 'e');
}
], function(err, arg1, arg2) {
console.log(err, arg1, arg2);
//=> null, 'd', 'e'
});
- Each function in
fns
is called in series. - Invoke the
cb
callback in each function to signal the end of the function. The signature of thecb
callback iscb(err [, arg1, arg2, ...])
:err
— If truthy, thedone
callback is called exactly once with theerr
.arg1, arg2, ...
— Arguments that are passed on to the next function infns
.
- When the entire series of functions has completed execution, the
done
callback is called exactly once with a falsyerr
and arguments from the last function infns
.
Install via npm:
$ npm i --save savoy
Install via bower:
$ bower i --save yuanqing/savoy
To use Savoy in the browser, include the minified script in your HTML:
<body>
<!-- ... -->
<script src="path/to/savoy.min.js"></script>
<script>
// savoy available here
</script>
</body>