Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/35.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript生成器:理解它们_Javascript_Node.js_Generator_Yield - Fatal编程技术网

Javascript生成器:理解它们

Javascript生成器:理解它们,javascript,node.js,generator,yield,Javascript,Node.js,Generator,Yield,我很确定我对发电机的理解是天生的。所有的在线资源似乎都存在冲突,这使得学习体验变得异常困难和混乱 据我所知,yield关键字使当前正在执行的代码块能够等待一个值,而不是在回调中抛出要执行的剩余代码。因此,正如大多数教程所指出的,您可以使用: (function *() { // Wait until users have be got and put into value of `results` var results = yield db.get("users");

我很确定我对发电机的理解是天生的。所有的在线资源似乎都存在冲突,这使得学习体验变得异常困难和混乱

据我所知,
yield
关键字使当前正在执行的代码块能够等待一个值,而不是在回调中抛出要执行的剩余代码。因此,正如大多数教程所指出的,您可以使用:

(function *() {
     // Wait until users have be got and put into value of `results`
     var results = yield db.get("users");
     // And continue
     view.display(results);
})();
而不是:

db.get("user", function(results) {
    view.display(results);
});
对,在我尝试编写自己的生成器之前,这一切都很好。我遇到了几个问题:

  • 我上面的第一个示例代码将不会运行,因为在生成器上没有可迭代的内容,对吗?某个更高的存在必须调用
    。下一个
    在某个地方,对吗
  • 整个API必须重写到I/O调用以支持生成器,对吗
  • 从我收集的资料来看,
    yield
    似乎代表等待大多数通用用例的值,而在实现部分(读:返回值到/inside
    db.get
    yield
    似乎代表将此值发送回当前等待的块以恢复执行
例如:

function *fn() {
    yield 1;
    yield "a";
}

var gen = fn();
gen.next(); // 1
gen.next(); // "a";
yield
在该上下文中,返回值而不是等待结果。在上面的第一个示例中,它等待来自
db.get
的结果,并继续执行,而不是“返回”或发回值。如果
db.get
的情况为真,那么这不是固有的同步吗?我的意思是,这和:

(function() {
     //Wait for the results
    var results = fs.readFileSync("users.txt");
    // Use results
    view.display(results);
})();

不幸的是,如果从这个问题(可能是唯一清楚的事情)可以看出我不理解生成器。希望我能在这里获得一些见解。

这两个例子并不相同。当您让步时,函数现在实际上变成了回调,等待db.get(“用户”)完成时执行。这样,函数就不会阻止其他函数的执行。可以将其视为一种通过让系统知道可以在某些点暂停来将同步函数转换为异步函数的方法

如果是生成器的一部分,则没有异步内容。生成器只是暂停并恢复代码块。当你使用我所说的“发电机引擎”时,所有的异步魔法都会发生

基本上,
gen.next()
所做的是返回最后一个
yield
ed值,并允许您在
yield
被分配给某个对象时返回一个值,例如
var something=yield 1
。因此,如果您有代码块:

function* genfun() {
  var a = yield 1
  var b = yield 2
}

var gen = genfun()

gen.next() // returns the first yielded value via `{value: 1}`
gen.next(1) // sets `a` as 1, returns the next yielded value via `{value: 2}`
gen.next(2) // sets `b` as 2, the generator is done, so it returns `{done: true}`
gen.throw(err)
与next相同,只是错误被抛出而不是分配给变量


这就是控制流引擎的工作原理-您将获得下一个值,它可能是回调或其他什么。执行回调,在回调完成之前不要执行gen.next()

TL;DR:generator的本质是控制代码执行的暂停。

对于发电机本身,您可以参考

总而言之,您应该区分三个部分: 1.生成函数 2.发电机 3.生成结果

生成器函数就是头上有星的
函数
,体上有(可选)
yield

function *generator() {
  console.log('Start!');
  var i = 0;
  while (true) {
    if (i < 3)
      yield i++;
  }
}

var gen = generator();
// nothing happens here!!
ret
以上是生成器结果。它有两个属性:
value
,即在生成器函数中生成的值;和
done
,一个指示生成器函数是否返回的标志

在这一点上,没有人会期望您了解发电机,至少不会了解发电机的异步功率

简单来说,generator有两个功能:

  • 可以选择跳出函数,让外部代码决定何时跳回函数
  • 异步调用的控制可以在代码之外完成
在代码中,
yield
跳出函数,而
next(val)
跳回函数并将值传递回函数。 外部代码可以处理异步调用,并决定适当的时间切换到您自己的代码

再次查看示例:

var gen = generator();
console.log('generated generator');
console.log(gen.next().value);
// mock long long processing
setTimeout(function() {
  console.log(gen.next().value);
  console.log('Execute after timer fire');
}, 1000);
console.log('Execute after timer set');

/* result:
    generated generator
    start
    0
    Execute after timer set
    1
    Execute after timer fire
*/
看到了吗?生成器函数本身不处理回调。外部代码可以

基地在这里。您可以详细说明这段代码,以支持完全异步,同时保持生成器功能与sync one类似

例如,假设
geturl
是一个异步调用,返回
promise
对象。您可以编写
var html=yield-getUrl('www.stackoverflow.com')此跳转到代码之外。外部代码将执行以下操作:

var ret = gen.next();
ret.then(function (fetchedHTML) {
  // jumps back to your generator function
  // and assign fetchHTML to html in your code
  gen.next(fetchedHTML);
});
有关更完整的指南,请参阅。
和存储库等。

尽管如此,关于生成器和产量的讨论仍然有效,可能有助于您的理解。也可能有助于(尤其是示例IMO)@VincentRamdhanie优秀的生成器解释!它教会了我发电机的另一种用法!使用ES6的无限滚动
var gen = generator();
console.log('generated generator');
console.log(gen.next().value);
// mock long long processing
setTimeout(function() {
  console.log(gen.next().value);
  console.log('Execute after timer fire');
}, 1000);
console.log('Execute after timer set');

/* result:
    generated generator
    start
    0
    Execute after timer set
    1
    Execute after timer fire
*/
var ret = gen.next();
ret.then(function (fetchedHTML) {
  // jumps back to your generator function
  // and assign fetchHTML to html in your code
  gen.next(fetchedHTML);
});