Does node.js support yield?

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 generator function which creates a lot of if (callback(arg) === false) return;

I want something like in python:

for p in primes():
  if p > 100: break
  do_something(p)

which I'm doing in node like this:

primes(function(p) {
  if (p > 100) return false;
  do_something(p)
});

Maybe something like coffeescript could help?


Solution 1:

Yes, since version 0.11. Enjoy!

http://wingolog.org/archives/2013/05/08/generators-in-v8

http://jlongster.com/A-Study-on-Solving-Callbacks-with-JavaScript-Generators

Solution 2:

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

Solution 3:

You can use generators in Node.js, but only in 0.11+. Node.js 0.12 (stable) is now available. Add --harmony_generators or --harmony to the command line parameters of node to enable it.

With Traceur, you can compile advanced JavaScript to vanilla JavaScript. You could make a loader for node.js that does this on-the-fly. Since it runs on, and compiles to vanilla JavaScript, it runs in node.js < 0.11 as well as in the browser.

Facebook has developed a lighter version that only supports generators, called Regenerator. It works similarly to Traceur.

Solution 4:

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);
            }
        });