为什么必须在节点应用程序的此语句中获得“yield”?

时间:2014-12-23 00:38:23

标签: node.js koa

当我尝试使用'koa-router'模块进行koa时,我看到了下面的示例代码片段。

app.get('/users/:id', function *(next) {
  var user = yield User.findOne(this.params.id);
  this.body = user;
});

我的问题是,为什么它在获取用户信息之前才有yield?为什么不能在没有收益的情况下编码如下有什么主要区别吗?

app.get('/users/:id', function *(next) {
  var user = User.findOne(this.params.id);
  this.body = user;
});

4 个答案:

答案 0 :(得分:3)

星号function *(){}的功能是生成器功能,允许使用暂停恢复流程yield关键字。

没有屈服的发电机功能是没用的,它们是齐头并进的。

koa 的幕后工作生成器函数由co库调用,该库处理所有异步操作,抽象 回调/承诺进入库,为您提供更简单的代码。

我在了解您可能会发现有用的生成器时创建了screencast

答案 1 :(得分:1)

我不认识koa。但它似乎使用和谐发生器(可从节点0.11获得)。

基本上第一部分与:

相同
app.get('/users/:id', function *(next) {
  var self = this;
  User.findOne(this.params.id).then(function(user) {
    self.body = user;
  });
});

当收益率承诺得到解决时,收益率将返回已实现的值,程序将从那里恢复。 function *(..)(据我所知)也是一个允许使用yield的特殊构造。

答案 2 :(得分:1)

因为正文将被设置为一个在将来不存在的值。

您可以将yield视为一种wait关键字,其中等待行为由Koa基础架构处理。你产生一个承诺,然后Koa等待履行的承诺,然后它再次调用你的生成器(实际上,基于生成器在迭代器上调用next()),使用promise的已解析值作为{的参数{1}},这意味着它会被分配到next左侧的变量。

所以在这种情况下,你进行数据库调用,产生对Koa的结果承诺,Koa等待它完成,然后传回分配给变量yield的已实现值,并且函数运行要么直到下一个产量,要么直到它从底部掉下来。

如果考虑如何在同一请求中处理两个异步任务,可能会更清楚:

user

在这种情况下,你“两次在蹦床上跳跃”。

根据您选择如何考虑这一点,您可以将其视为更具可读性的等同于

app.get('/users/:id', function *(next) {
    var user = yield User.findOne(this.params.id);
    var data = yield someOtherAsynchronousTaskReturningProimse(user);
    this.body = data;
});

我认为你会同意所谓的“基于共同例程”的方法更具可读性。除了允许您以function handle(id) { User.findOne(id) .then(function(user) { someOtherAsynchronousTaskReturningPromise(user) .then(function(data) { setDataIntoResponse(data); }); }); } 方式编写中间件/处理程序之外,这种体系结构的另一个优点是,Koa可以在等待您回来解决的承诺时继续做其他有用的事情。

答案 3 :(得分:0)

KOA使用生成器函数来简化所谓的中间件的注入。来自KOA的网站(http://koajs.com/):

  

当中间件调用yield next时,函数会挂起并传递   控制到下一个定义的中间件。之后就没有了   中间件执行下游,堆栈将放松和每个   中间件恢复执行其上游行为。

示例:

var app = Koa();

app.use (function* (next) {
    this.body = '{';
    yield next;
    this.body += '}';
});

app.use (function* () {
    this.body += 'Hello World!';
});

此网络服务器将使用字符串'{Hello World!}'进行响应。为什么?执行流入第一个生成器函数,将body设置为“{”并暂停在yield next。执行继续下一个生成器函数并附加“Hello World!”。该函数结束,因此执行流回第一个暂停的位置,附加'}'。

然而,在你的情况下,只要使用yield来传递next之外的其他内容,它会更复杂一些。例如,在KOA中,您也可以产生承诺。看看这个(我在这里找到:http://blog.stevensanderson.com/2013/12/21/experiments-with-koa-and-javascript-generators/

app.use(function *() {
    var response = yield doHttpRequest('http://example.com/');
    this.body = "Response length is " + response.body.length;
});

在此示例中,yield从异步Http请求传递promise(由辅助函数doHttpRequest完成,此处未显示)。 KOA暂停该功能,直到履行承诺,然后继续执行“this.body = ...”。在你的代码片段中,User.findOne()可能会返回这样的承诺。 (不一定; KOA允许您传回其他类型的对象,请参阅文档。)