Thursday, March 2, 2017

Koa.js - Generators

One of the most exciting new features coming in JavaScript ES6 is a new breed of function, called a generator. Before generators, the whole script used to usually execute in a top to bottom order, without an easy way to stop code execution and resuming with the same stack later. Generators are functions which can be exited and later re-entered.
Their context (variable bindings) will be saved across re-entrances.
Generators allow us to stop code execution in between. So lets have a look at a simple generator:
var generator_func = function* (){
 yield 1;
 yield 2;
};

var itr = generator_func();
console.log(itr.next());
console.log(itr.next());
console.log(itr.next());
When running the above code, we the the result:
{ value: 1, done: false }
{ value: 2, done: false }
{ value: undefined, done: true }
Lets look inside the above code. We first create a generator called generator_func(). We created an instance of this weird looking function and assigned it to itr. Then we started calling next() on this itr variable. Calling next() starts the generator and it runs until it hits a yield. Then it returns the object with value and done, where value has the expression value. This expression can be anything. At this point it pauses execution. Again when we call this function(next), generator resumes execution from last yield point with the function state being the same at time of pause, till the next yield point. This is done till there are no more yield points in the code.

Generators in Koa

So why are we discussing generators in this tutorial. As you might remember from the hello world program, we used a function* () notation to pass a callback to app.use(). Koa is an object which contains an array of middleware generator functions, all of which are composed and executed in a stack-like manner upon each request. Koa also implements downstreaming followed by upstreaming of control flow. Look at the following example to understand this in a better way:
var koa = require('koa');
var app = koa();
 
app.use(function* (next) {
    //do something before yielding to next generator function 
    //in line which will be 1st event in downstream
    
    console.log("1");
    yield next;
 
    // do something when the execution returns upstream, 
    //this will be last event in upstream
    console.log("2");
});
 
app.use(function* (next) {
    // This shall be 2nd event downstream
    
    console.log("3");
    yield next;
 
    // This would be 2nd event upstream
    console.log("4");
});
 
app.use(function* () { 

 // Here it would be last function downstream
    console.log("5");
    
    // Set response body
    this.body = "Hello Generators";

    // First event of upstream (from the last to first)
    console.log("6"); 
 
});
 
app.listen(3000);
When running the above code and navigating to https://localhost:3000/ we get the following output on our console:
1
3
5
6
4
2
This is essentially how koa uses generators. It allows us to create compact middlewares using this property and write code for both up and down stream functionalities, thus saving us from callbacks.

No comments:

Post a Comment