对象生成器函数没有做它应该做的事情并且没有返回结果。

时间:2017-06-16 15:49:39

标签: javascript node.js yield

我试图学习如何使用对象生成器并使用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;
}

2 个答案:

答案 0 :(得分:2)

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

另一方面,承诺代表了一种尚未存在但可能在未来某个时间存在的价值。 ES6还为我们提供了async functions,它简化了使用await关键字的承诺。以下是使用异步函数查看代码的方式:

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

答案 1 :(得分:1)

首先,我认为你必须检查一些生成器教程。对于使用生成器,您必须首先创建生成器然后使用它,以便您的代码变为如下:

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函数的第一个参数传递,并且您的next函数的返回值是具有以下形式的对象:

{
  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

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