Javascript生成器:了解它们

Adr*_*ney 20 javascript yield generator node.js

我很确定我对发电机的理解本质上已被打破.所有在线资源似乎都存在冲突,这会带来令人难以置信的困难和令人困惑的学习体验.

据我所知,该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);
})();
Run Code Online (Sandbox Code Playgroud)

代替:

db.get("user", function(results) {
    view.display(results);
});
Run Code Online (Sandbox Code Playgroud)

是的,在我尝试编写自己的发电机之前,这一切都很好.我遇到了几个问题:

  • 上面的第一个示例代码将不会运行,因为没有任何东西可以迭代生成器,对吗?有些人需要打电话给.next某个地方,对吗?
  • 整个API必须重写到I/O调用以支持生成器,对吗?
  • 从我收集的内容来看,yield似乎代表值等待最常见的用例,而在实现部分(读取:返回值为/ inside db.get)yield似乎代表将此值发送回当前正在等待的块以恢复执行.

举个例子:

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

var gen = fn();
gen.next(); // 1
gen.next(); // "a";
Run Code Online (Sandbox Code Playgroud)

yield在该上下文中,将值返回而不是等待结果.在上面的第一个示例中,它等待来自db.get和恢复执行的结果,而不是"返回"或发回一个值.如果db.get情况属实,这本身并不是同步的吗?我的意思是,它不完全相同:

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

不幸的是,如果从这个问题中明确表示(可能唯一清楚的是)我不了解发电机.希望我能在这里获得一些见解.

Her*_*lme 21

TL; DR:生成器的本质是控制代码执行的暂停.

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

总而言之,您应该区分三个组件:1.生成器功能2.生成器3.生成结果

发电机功能简单就是function头部的星形和(可选)yield的身体.

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

var gen = generator();
// nothing happens here!!
Run Code Online (Sandbox Code Playgroud)

在上面的情况下,发电机功能本身不做任何事情,只返回发电机gen.这里因为只返回后无控制台输出生成next方法被调用的身体产生功能将运行.Generator有几种方法,其中最重要的是next.next运行代码并返回生成器结果.

var ret = gen.next();
// Start!
console.log(ret);
// {value: 0, done: false}
Run Code Online (Sandbox Code Playgroud)

ret以上是发电机结果.它有两个属性:value,你在生成器函数产生的值,以及done一个指示生成器函数是否返回的标志.

console.log(gen.next());
// {value: 1, done: false}
console.log(gen.next());
// {value: 2, done: false}
console.log(gen.next());
// {value: undefined, done: true}
Run Code Online (Sandbox Code Playgroud)

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

简而言之,发电机有两个特点:

  • 可以选择跳出函数并让外部代码确定何时跳回函数.
  • 异步调用的控制可以在代码之外完成

在代码中,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
*/
Run Code Online (Sandbox Code Playgroud)

看到?生成器函数本身不处理回调.外部代码可以.

基地就在这里.您可以详细说明此代码以支持完全异步,同时保持生成器功能,如同步.

例如,假设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);
});
Run Code Online (Sandbox Code Playgroud)

有关更完整的指南,请参阅此内容.和co,galaxy,suspend等存储库一样