Does node.js support yield?

后端 未结 10 666
误落风尘
误落风尘 2021-01-31 01:51

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

相关标签:
10条回答
  • 2021-01-31 02:32

    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:

    • Generators
    • Generator functions
    • Iterable Protocol
    • Iterator Protocol
    • Async Generators
      • Jake Archibald's Article on Async Generators
    • Async Iterators
    • for await ... of
    0 讨论(0)
  • 2021-01-31 02:34

    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);
                }
            });
    
    0 讨论(0)
  • 2021-01-31 02:35

    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.

    0 讨论(0)
  • 2021-01-31 02:46

    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

    0 讨论(0)
  • 2021-01-31 02:48

    You might check out wu.js at http://fitzgen.github.com/wu.js/ It has lots of interesting iterator functions.

    0 讨论(0)
  • 2021-01-31 02:48

    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
    })
    
    0 讨论(0)
提交回复
热议问题