在ES6生成器函数

时间:2016-05-13 06:08:54

标签: javascript node.js ecmascript-6

如果你使用return语句而不是yield,我很难找到会发生什么。

function *gen(){

 const val = yield someAsyncFn();
 assert.equal(val,4);
 return val;

}

退货的收益与收益率有何不同?我假设return作为一个普通的return语句,但是生成器函数的上下文,它是否也调用gen.return()?有点令人困惑。

也许以上只是与此相同?

   function *gen(){

     const val = yield someAsyncFn();
     assert.equal(val,4);
     yield val;

   }

2 个答案:

答案 0 :(得分:17)

return为迭代器的最后一次迭代提供了一个返回值(当done等于true时)。

我已经简化了您的示例,因为异步操作似乎与问题无关:

function *gen(){
 const val = yield 4;
 return val * 2;
}

var it = gen();
var val = it.next(); // { value: 4, done: false }
console.log(val.value); // 4
var res = it.next(val.value); // { value: 8, done: true }
console.log(res.value); // 8

如果没有return值,在最后一次迭代中,您将返回undefined的值:

function *gen2(){
 const val = yield 4;
 yield val * 2;
}

var it2 = gen2();
var val2 = it2.next(); // { value: 4, done: false }
console.log(val2.value); // 4
var res2 = it2.next(val2.value); // { value: 8, done: false }
console.log(res2.value); // 8
it2.next(); // { value: undefined, done: true }

旁注:根据经验,总有一个next调用,然后有yield个语句,这就是为什么还有一个下一个调用的原因。第二个例子。

让我们说你使用像co这样的生成器运行器,然后在完成生成器后得到的值就是return的值:

co(function* () {
  var result = yield Promise.resolve(true);
  return result;
}).then(function (value) {
  console.log(value); // value equals result
}, function (err) {
  console.error(err.stack);  // err equals result
});

重要提示:如果您正在迭代迭代器,使用for ... of循环或Array.from之类的东西,return值将被忽略(由于您正在进行异步操作,因此可能并非如此):

function *gen(){
 const val = yield 4;
 return val * 2;
}

for (let value of gen()) {
  console.log(value);
}
// 4

最后,调用生成器只会创建一个interator。迭代器返回的最终值是否相关,完全取决于您如何使用它。

答案 1 :(得分:2)

除了@nils的详尽回答外,还有另一种方法来捕获生成器函数的返回值,即yield*的值(必须在另一个生成器函数内部):

  function* arrayGenerator(arr) {
    for (const element of arr) 
      yield element
    return arr.length
  }

  function* elementsFollowedByLength(arr) {
    const len = yield* arrayGenerator(arr);
    yield len;
  }

请注意,在生成数组元素之后,第一个生成器函数将返回一个值。

第二个生成器函数通过yield*导致第一个生成器函数产生其所有值。当第一个生成器函数完成并返回时,该返回值将成为yield*表达式的值。