Because the body would be set to a value which won't exist until the future.
You can think of the yield
here as a kind of wait
keyword, where the waiting behavior is being handled by the Koa infrastructure. You yield a promise, then Koa waits for the promise to fulfill, then it calls your generator again (well, actually, calls next()
on the iterator based on the generator), using the promise's resolved value as the argument to next
, which means it gets assigned to the variable on the left-hand side of the yield
.
So in this case, you make the DB call, yield the resulting promise to Koa, Koa waits for it to fulfill, then passes back the fulfilled value which is assigned to the variable user
, and the function runs either until the next yield, or until it falls off the bottom.
It might be clearer if you consider how you would handle two asynchronous tasks in the same request:
app.get('/users/:id', function *(next) {
var user = yield User.findOne(this.params.id);
var data = yield someOtherAsynchronousTaskReturningProimse(user);
this.body = data;
});
In this case, you are "jumping up and down on the trampoline" twice.
Depending on how you choose to think of this, you can sorta kinda treat this as the more readable equivalent of something like
function handle(id) {
User.findOne(id)
.then(function(user) {
someOtherAsynchronousTaskReturningPromise(user)
.then(function(data) {
setDataIntoResponse(data);
});
});
}
I think you'll agree that the so-called "co-routine" based approach is much more readable. Another advantage of this architecture, besides allowing you to write your middleware/handlers in yield...yield
fashion, is that Koa can go about doing other useful things while it's waiting for the promise you returned to resolve.