【问题标题】:Does node.js support yield?node.js 是否支持产量?
【发布时间】:2011-05-06 19:30:41
【问题描述】:

有没有办法让generators 进入 node.js?

我目前正在使用回调来伪造它们,但我必须记住检查生成器函数内部的回调响应,这会创建很多 if (callback(arg) === false) return;

我想要类似 python 的东西:

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

我在这样的节点中做的事情:

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

也许像coffeescript 这样的东西可以提供帮助?

【问题讨论】:

标签: node.js generator


【解决方案1】:

【讨论】:

  • 但他们当前的版本是v0.10.24,我很困惑。
  • 最新的稳定版本是 v.0.10.24,但你总是可以得到一个不稳定的版本here(目前是 v0.11.10)。版本总是在节点blog(带有变更日志)中公布。 v0.11.10 文档是here。这应该不难找到,从Nodejs.org home page > Downloads > Other releases
  • 我无法让它们工作,即使在节点 v0.10.29 中有 --harmony 标志。
  • @Mark,和谐标志仅适用于 Node 的“不稳定”版本(v0.11.12)。如果您想尝试一下,但仍然可以轻松切换回当前的“稳定”版本,我建议您安装 nvm (github.com/creationix/nvm 或者如果您使用 fish shell github.com/Alex7Kom/nvm-fish :) 并安装最新的不稳定版本,并在那些生成器上大打出手。
  • @ADRegan 看起来我在写该评论时没有阅读此线程中的任何其他内容;最终发现我需要 0.11.x :-) 谢谢。我是 Windows 用户;发现nodist 非常适合管理节点版本。
【解决方案2】:

答案是“目前还没有”,但马塞尔似乎是我的英雄。让我们希望这会发生在某个地方:

https://groups.google.com/forum/#!msg/nodejs/BNs3OsDYsYw/oCsWBw9AWC0J https://github.com/laverdet/node-fibers

【讨论】:

    【解决方案3】:

    您可以在 Node.js 中使用生成器,但只能在 0.11+ 中使用。 Node.js 0.12(稳定版)现在可用。在node的命令行参数中添加--harmony_generators--harmony来启用它。

    使用Traceur,您可以将高级 JavaScript 编译为普通 JavaScript。您可以为 node.js 制作一个加载器,它可以即时执行此操作。由于它可以运行并编译为原生 JavaScript,因此它可以在 node.js

    Facebook 开发了一个只支持生成器的轻量级版本,称为Regenerator。它的工作原理与 Traceur 类似。

    【讨论】:

      【解决方案4】:

      显然不在当前的稳定版本中。但是,您可以使用 node-fibers + promises 来实现相同的目标。

      这是我的实现:

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

      还有一个关于它如何工作的示例代码:(query.find 返回一个承诺)

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

      【讨论】:

      • 能否请您也发布源代码以供查询?它可以与任何回调系统一起使用吗?
      【解决方案5】:

      您可以查看 http://fitzgen.github.com/wu.js/ 的 wu.js,它有很多有趣的迭代器函数。

      【讨论】:

        【解决方案6】:

        是和不是。

        var myGen = (function () {
            var i = 0;
            return function () {
                i++; return i; }
        })();
        var i;
        while ((i = myGen()) < 100 ) {
            do something; }
        

        如您所见,您可以使用闭包来实现类似的东西,但它没有本地生成器。

        【讨论】:

          【解决方案7】:

          v8 中的 issue 提议生成器最近已被 v8 项目成员接受。
          请投票yield 成为现实。

          【讨论】:

            【解决方案8】:

            2014 年更新:Node 现在支持回调。以下是 2010 年的帖子。


            您应该使用回调。如果函数异步执行某些操作,您可能还需要一个延续回调(延续是一个坏词,因为它还有其他含义,但你明白我的意思。)

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

            已更新示例代码

            我翻转了它,使它在完成时返回 true(因为 null、false 和 undefined 无论如何都评估为 false)。

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

            【讨论】:

            • 但是我的primes 函数中充斥着if (callback(arg) === false) return; 而不仅仅是yield arg。应该这么丑吗?
            • do { /* setup callback data */ } while(callback(arg)); continuation() ?请记住,函数内部的外观并不重要,只要接口和输出良好即可。
            • 哦,关于你的 primes 函数(我假设你在那里做了一些复杂的嵌套),你需要以这样的方式编码它,它可以删除所有内容,移动到回调,然后在下一次迭代中重新开始(使用临时变量来保持状态),否则您将不得不忍受多个回调行。
            【解决方案9】:

            我们在节点 https://github.com/TooTallNate/gnode 中使用 gnode 生成器

            【讨论】:

              【解决方案10】:

              是的,Node.js 和 JavaScript 现在同时具有同步迭代器(至少从 Node v6 开始)和异步迭代器(从 Node v10 开始):

              具有同步输出的示例生成器/迭代器:

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

              类似的异步生成器/迭代器。

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

              这里有很多值得探索的地方,有一些很好的链接。稍后我可能会用更多信息更新这个答案:

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2017-01-27
                • 1970-01-01
                • 2019-03-13
                • 2021-05-08
                • 1970-01-01
                • 2011-02-06
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多