【问题标题】:Object generator function not doing what it should and returning no result.对象生成器函数没有做它应该做的并且不返回任何结果。
【发布时间】:2017-11-19 11:18:04
【问题描述】:

我正在尝试学习如何使用对象生成器并使用 yield 命令在我的 nodejs 控制器中执行一些同步操作。

我希望它首先执行 FOO 调用,然后在返回时执行 BAR 调用。

在这种情况下,我希望控制台显示

Hello FOO
Hello BAR

但我得到的只是

Result [object Generator]
Result [object Generator]

我什至没有在函数中获取 console.logs。

  var myResult = findUser1("FOO")
  console.log("Result " + myResult )

  myResult = findUser1("BAR")
  console.log("Result " + myResult )

function* findUser1(UID) {
    var user1 = yield setTimeout("Hello " + UID, 2000);
    console.log("This should be shown AFTER user1 has a result");
    console.log(user1);
    return user1;
}

【问题讨论】:

    标签: javascript node.js yield


    【解决方案1】:

    我相信您正在寻找promises,而不是生成器函数。生成器函数返回 IterableIterator 对象。这些对象遵循iterator protocol,这意味着它们有一个next() 方法,该方法返回一个带有value 字段和done 布尔字段的对象。它们还遵守iterable protocol,这意味着它们有一个特殊的@@iterator 方法,该方法返回一个迭代器对象(在这种情况下,它返回自身,因为它是它自己的迭代器)。

    另一方面,Promise 表示一个尚不存在但可能在未来某个时间存在的值。 ES6 还给了我们async functions,它简化了使用带有await 关键字的promise。以下是您的代码使用异步函数的外观:

    async function findUser(id) {
      const user = await new Promise((resolve, reject) => {
        setTimeout(() => resolve("Hello " + id), 2000);
      });
      console.log("This should be shown AFTER user has a result");
      console.log(user);
      return user;
    }
    
    async function getUsers() {
      const user1 = await findUser("FOO");
      console.log("Result " + user1);
      const user2 = await findUser("BAR");
      console.log("Result " + user2);
    }
    
    getUsers();
    

    如果你不想使用async/await语法,下面是等价的:

    function findUser(id) {
      return new Promise((resolve, reject) => {
        setTimeout(() => resolve("Hello " + id), 2000);
      }).then((user) => {
        console.log("This should be shown AFTER user has a result");
        console.log(user);
        return user;
      });
    }
    
    findUser("FOO")
      .then(user1 => console.log("Result " + user1))
      .then(() => findUser("BAR"))
      .then(user2 => console.log("Result " + user2));
    

    【讨论】:

    • 哇哦!!!我什至不知道有 async function 东西 - 我会马上试试你的例子!!
    • 我收到一个奇怪的错误:async function findUser(id) {SyntaxError: Unexpected token function 你能帮忙吗?
    • @torbenrudgaard 您使用的是什么版本的节点?如果您将这段代码复制并粘贴到最新版本的 Chrome 控制台中,这两个版本的代码都可以工作,并且现代版本的 Node 支持异步函数(甚至是异步生成器函数)
    • @torbenrudgaard 您至少需要使用 Node 7.6,或者使用 babel 和 babel-plugin-transform-async-to-generator 转译代码。但如果您可以升级到 Node 7 或 8,我强烈推荐它,因为您可以获得对更多 ES6 功能的原生支持!
    • 啊! v6.11.0 LTS Recommended For Most Users我想这就是当你遵循指南时会发生的事情嘿嘿嘿...让我更新到版本 8.1.2
    【解决方案2】:

    首先,我认为您必须查看一些生成器教程。要使用生成器,您必须先创建生成器然后使用它,这样您的代码才会变成这样:

    var findUser = findUser("FOO");
    var myResult = findUser.next().value;
    console.log("Result " + myResult );
    findUser.next();
    
    
    function* findUser1(UID) {
        var user1 = yield setTimeout(() => {"Hello " + UID}, 2000);
        console.log("This should be shown AFTER user1 has a result");
        console.log(user1);
        return user1;
    }
    

    请注意,您必须将回调函数作为setTimeout函数的第一个参数传递,并且您的下一个函数的返回值是一个具有以下形式的对象:

    {
      value: ...,
      done: false
    }
    

    并且在您的应用程序中是从超时函数返回的对象,为了完成您的函数,您必须再次调用next()。 请注意,您的生成器中的yield 命令将传递给next() 的内容返回给您。

    最后让我们回顾一下使用生成器创建控制流的一些方法:

    function asyncFlow(generatorFunction) {
      function callback(err) {
        if (err) {
          return generator.throw(err);
        }
        const results = [].slice.call(arguments, 1);
        generator.next(results.length > 1 ? results : results[0]);
      }
      const generator = generatorFunction(callback);
      generator.next();
    }
    
    asyncFlow(function* (callback) {
      console.log('1. Hello');
      yield setTimeout(callback, 2000);
      console.log('2. 2000ms');
      yield setTimeout(callback, 1000);
      console.log('3. 1000ms');
    });
    

    co 是一个很好的基于生成器的控制流库,你可以找到它的详细信息here

    除了生成器,您还可以使用原生 js 或 ECMA2017 的 async 功能来管理您的控制流。

    【讨论】:

    • 您好帕勒姆,感谢您的回答。我实际上尝试了几个教程,但其中许多都不像他们描述的那样工作,而其他的真的很难理解。所以你必须先创建生成器,我现在就试试。
    • 我会尝试在我的回答中添加更多细节来帮助你更多,你想在 nodejs 中使用生成器创建同步函数吗?
    • 我需要做的是找到一个用户,如果他存在做一些事情,然后找到另一个用户等。我尝试了承诺,但它变得太乱了(回调地狱) - 所以我决定尝试学习生成器。我刚刚尝试了您的示例并得到 3 行:Result [object Object] 和 ` 这应该在 user1 有结果后显示`和 `undefined`
    • @torbenrudgaard 你看到我用async/await 语法回答了吗?没有回调地狱的承诺!
    猜你喜欢
    • 2021-02-02
    • 1970-01-01
    • 1970-01-01
    • 2011-09-28
    • 2020-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-14
    相关资源
    最近更新 更多