Is there any way to get generators into node.js?
I\'m currently faking them with callbacks, but I have to remember to check the response of the callback inside of my gen
Yes Node.js and JavaScript now have both synchronous iterators (as of atleast Node v6) and asynchronous iterators (as of Node v10):
An example generator/iterator with synchronous output:
// semi-pythonic like range
function* range(begin=0, end, step=1) {
if(typeof end === "undefined") {
end = begin;
begin = 0;
}
for(let i = begin; i < end; i += step) {
yield i;
}
}
for(const number of range(1,30)) {
console.log(number);
}
A similar async generator/iterator.
const timeout = (ms=1000) => new Promise((resolve, reject) => setTimeout(resolve, ms));
async function* countSeconds(begin=0, end, step=1) {
if(typeof end === "undefined") {
end = begin;
begin = 0;
}
for(let i = begin; i < end; i += step) {
yield i;
await timeout(1000);
}
}
(async () => {
for await (const second of countSeconds(10)) {
console.log(second);
}
})();
There is a lot to explore here are some good links. I will probably update this answer with more information later:
Apparently not in the current stable version. You can however achieve the same using node-fibers + promises.
Here is my implementation:
var fiber = require('fibers');
module.exports.yield = function (promise) {
var currentFiber = fiber.current;
promise
.then(function (value) {
currentFiber.run(value);
})
.otherwise(function (reason) {
currentFiber.throwInto(reason);
});
return fiber.yield();
};
module.exports.spawn = function (makeGenerator) {
fiber(function () {
makeGenerator.apply(this, Array.prototype.slice.call(arguments, 1));
}).run();
};
And a sample code on how it works: (query.find returns a promise)
var generators = require('./utils/generators');
var query = require('./utils/query');
generators.spawn(function () {
try {
var field1 = generators.yield(query.find('user', { _id : '1' }));
var field2 = generators.yield(query.find('user', { _id : '2' }));
console.log('success', field1[0]._id, field2[0]._id);
}
catch (e) {
console.error('error', e);
}
});
Yes and no.
var myGen = (function () {
var i = 0;
return function () {
i++; return i; }
})();
var i;
while ((i = myGen()) < 100 ) {
do something; }
As you see, you can implement something like one using closures, but it does not have native generators.
The answer is "not currently" but Marcel seems to be my hero. Lets hope this goes somewhere:
https://groups.google.com/forum/#!msg/nodejs/BNs3OsDYsYw/oCsWBw9AWC0J https://github.com/laverdet/node-fibers
You might check out wu.js at http://fitzgen.github.com/wu.js/ It has lots of interesting iterator functions.
Update 2014: Node does support callbacks now. The following is a post from 2010.
You should use callbacks. If the function does something asynchronously, you may also want a continuation callback (continuation is a bad word, since it also means something else, but you get my point.)
primes(function(p) {
if (p > 100) return false // i assume this stops the yielding
do_something(p)
return true // it's also better to be consistent
}, function(err) { // fire when the yield callback returns false
if (err) throw err // error from whatever asynch thing you did
// continue...
})
Updated with example code
I flipped it, so that it returns true on complete (since null, false and undefined all evaluate to false anyways).
function primes(callback) {
var n = 1, a = true;
search: while (a) {
n += 1;
for (var i = 2; i <= Math.sqrt(n); i += 1)
if (n % i == 0)
continue search;
if (callback(n)) return
}
}
primes(function(p) {
console.log(p)
if (p > 100) return true
})