TODO: npm
Require js-iterator. TODO: npm
var Iterator = require('js-iterator');
On creation,
iterators take a next
function
in node callback style.
To get the next value from the iterator,
call its next
method.
// cb(err, item)
function nextRandom(cb) {
cb(null, Math.random());
}
var it = new Iterator(nextRandom);
it.next(function (err, item) {
console.log(item);
});
0.13976101111620665
The random iterator is infinite,
so conversion to an array would take forever.
But we can constrain the length using take
and then get an array of the finite sequence using toArray
.
it.take(5).toArray(function (err, result) {
console.log(result);
});
[ 0.8878921919967979,
0.8639499587006867,
0.8767323752399534,
0.7335713140200824,
0.9920800605323166 ]
To convert the random real sequence [0,1)
into a random integer sequence [1,6]
use the map
method.
var d6 = it.map(function (x) {
return Math.floor(x * 6) + 1;
});
d6.take(4).toArray(function (err, result) {
console.log(result);
});
[ 6, 1, 4, 1 ]
To keep track of how many times we rolled the d6,
use the zipWithIndex
method.
d6.take(4).zipWithIndex().toArray(function (err, result) {
console.log(result);
});
[ [ 6, 0 ],
[ 6, 1 ],
[ 4, 2 ],
[ 2, 3 ] ]
Create a new iterator from a next
function.
On each iteration,
next
will be called once,
and the result will be passed to the callback.
To terminate the iterator,
return undefined
.
If an exception is thrown,
it will be caught and passed as the err
of the consumer callback.
var n = 0;
var it = new Iterator(function () {
if (n < 3) {
return n++;
} else {
return;
}
});
it.toArray(function (err, result) {
console.log(result);
});
[ 0, 1, 2 ]
The next
function may also be asynchronous.
var n = 0;
new Iterator(function (cb) {
setTimeout(function () {
if (n < 3) {
return cb(null, n++);
} else {
return cb();
}
}, 0);
}).toArray(function (err, result) {
console.log(result);
});
There are many libraries that look similar to this one. There are the reactive projects, Kefir.js, RxJS and Bacon.js, which look promising for event processing. There are monads in Javascript, monet.js. There is the ever popular async library and its siblings: Async.js, Step. There are jQuery and Underscore, both of which support maps and filters and such. There are node streams and mongoose streams If I have missed some project worth mention here, please let me know.
But none of these actually support my main use case, which is to make it super simple setup affected data sources. E.g.
Source
.findIterator(query)
.filter(triageTooComplicatedForQuery)
.map(removePrivateData)
.map(proprietaryMangling)
.take(27)
.toArray(standardResult(res));
- Provide a callback-based iterator pattern.
- Consumers:
next
,forEach
,toArray
. - Chainable modifiers:
filter
,fold
,map
,take
,zip
. - Consolidated error handling, the first error gets returned.