Introduction to Generators & Koa.js: Part 1

Koa.js is an expressive next-generation web framework written for Node.js by the people behind the Express and Connect frameworks. Koa.js leverages generators, which are a bleeding edge feature of JavaScript, and have not yet been made into stable versions of Node.js. Koa aims to use generators to save developers from the spaghetti of callbacks, making it less error-prone and thus more manageable.

With just 550 lines of code, Koa is an extremely light framework. Even after that, Koa packs in an elegant suite of methods such as content-negotiation, redirections, proxy support etc., giving you ease and speed of development along with the granular control over your node application.

Installing Node

Now before we begin, you will need to have at least Node version 0.11.x or greater.

You can install the latest version of Node using the N module :

You can also use other community modules like nvm or build it from source. Please note that N is also a community module.

To run a JS file which makes use of generators, you need to provide the --harmony flag when you run it.

For example, to run app.js, enter in the following command:

Or to save yourself from entering this flag every time,  you can create an alias using the following command:

Now to run your application using generators, just enter:

Very good! Also keep in mind that all of the code in this article is available on GitHub. Feel free to fork and play with it.

Now to understand Koa, you must first understand generators which form the spine of the framework.

What Are Generators?

With ES-6, generators have finally landed in the magical land of JavaScript. If you have prior experience with generators in Lua, Python, Scheme, Smalltalk etc., then you would be glad to know that a very similar thing has been implemented in JavaScript. 

 Generators are first class co-routines in JavaScript which, simply put, introduces a pause and play interface in the language. 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. Now lets get our hands dirty with some examples.

As per the current draft ES-6 specification, we need to use a different version of the function definition to create a generator function. It looks like this:

Here generator_func is just an empty generator function.

So what we can do is use the yield keyword in the function to stop the execution and save the current stack.

Here's a simple example demonstrating the Sum of an infinite AP:

In the above code, we initially create an iterator instance named infinite_ap which includes an infinite loop and if run under normal conditions, can freeze the execution.

Next we store an iterator instance in the sum variable.

Now when we call sum.next(), it returns { value: 8, done: false } which means it stopped its execution on the yield statement returning the value as 'a' and done as 'false' .

Here done returns false until the execution is unfinished. Once the execution is complete (in the aforementioned case, it never happens) the function returns {value: undefined, done: true} .

Here is a small modification of the previous code to demonstrate the end of execution:

In more complex programs, you would check and use the values returned and the done status.

Note: Using yield without function* would lead to an early error.

Available Generators Methods

Here are some common methods that will come in handy when you deal with vanilla generators.

Each of the methods below is available only in a generator function and would throw an error otherwise.

next()

This is used to resume the execution along with passing an argument. If nothing is passed, then undefined gets passed as the first argument.

Example: sum.next(5);

throw()

This is used to throw an error or exception at any step. It makes error handling much easier. Throwing an error can result in stopping execution of the file, if it is not handled somewhere. The simplest way to handle an error is to use a try and catch statement. This method takes a single argument which can be anything.

Example: sum.throw(new Error("this is an error")); 

Delegating yield

Generator delegation is used to yield a generator from within an existing generator and can be used to compose generators or even iterate over a generator.

On delegating to another generator, the current generator stops producing a value itself and starts yielding values of the delegated generator until it is exhausted. Upon exhaustion of the delegated generator, the generator resumes returning its own value.

It is very much like using a for-in loop over a generator, but the exceptions of the delegated generator are propagated and thrown via the outer generator's throw method and should be handled likewise. Here's an example:

Now that you have a brief understanding of generators in Javascript , you can use them for writing much clearer and less error-prone applications where you can block on I/O, without actually blocking the process. 

Let's now move on to the installation of Koa and a very simple application based on Koa.js.

Koa.js:

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.

Installing Koa

In your project directory, execute the following command.

Koa will automatically be downloaded and saved in a package.json file, if it exists.

Despite Koa's very small footprint, it includes methods for tasks like cache freshness, content-negotiation, redirections, proxy support etc., with no middleware bundled in.

Here's an example hello-world application:

Koa's Control Flow

NowKoa also implements downstreaming followed by upstreaming of control flow. At first it can be hard to gasp, but once you go through the example below, things will get clearer.

Here's an example of control flow in Koa:

The code above is pretty simple. Note that not all console.log statements are required but they will help you to clearly understand the downstream and upstream execution flow of Koa.js .

Understanding the Examples' Execution Flow

When we run this application and open up localhost:3000 in the browser, we can observe that the console.logs in the terminal are not in the order of A-B-C-D-E-F. Nor are they in the order of A-C-E-B-D-F.

The order is actually A-C-E-F-D-B which depicts the downstream of yields and upstream behavior of the execution in a Koa app.

You might notice that it is printed twice. This is due to a double request sent by the browser to fetch the favicon.

Tip: The koa.use(function) adds the middleware function to the application.

In Conclusion

So that's it for part one of this tutorial on JavaScript generators and Koa.js. You've learned about most of the prerequisites such as what generators are, how to use use them, how to use delegating yield and how control flow works in Koa.js.

In the next part of this tutorial, we will dive deeper into Koa and learn how to build a CRUD application. If you have any questions or comments, feel free to contact me or just drop a comment below. 

Tags:

Comments

Related Articles