Node 7.6 + Koa 2: asynchronous flow control made right

Carlos Vega
Feb 23, 2017 · 5 min read

The problem with async operations

fs.readdir(source, function (err, files) {
if (err) {
console.log('Error finding files: ' + err)
} else {
files.forEach(function (filename, fileIndex) {
console.log(filename)
gm(source + filename).size(function (err, values) {
if (err) {
console.log('Error identifying file size: ' + err)
} else {
console.log(filename + ' : ' + values)
aspect = (values.width / values.height)
widths.forEach(function (width, widthIndex) {
height = Math.round(width / aspect)
console.log('resizing ' + filename + 'to ' + height + 'x' + height)
this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) {
if (err) console.log('Error writing file: ' + err)
})
}.bind(this))
}
})
})
}
})

Enter Koa 2

Frameworks such as Express heavily relied on callbacks to perform asynchronous actions and while it’s possible to write fairly clean and readable code using callbacks not every developer out there will know how or even care about doing so. At first, Koa got rid of the aforementioned callback hell using a combination of Promises and Generators but now that we have the async/await syntax available in Node Current we can make use of it.

const koa = require('koa');
const app = new koa();
app.use(function *(next){
var start = new Date;
yield next;
var ms = new Date - start;
console.log('%s %s - %s', this.method, this.url, ms);
});
app.use(function *(){
this.body = 'Hello World';
});

app.listen(3000);
const koa = require('koa');
const app = new koa();
app.use(async (ctx, next) => {
const start = new Date;
console.log(`Started at: ${start}`);
await next();
const ms = new Date - start;
console.log(`Elapsed: ${ms}ms`);
});
app.use(async (ctx) => {
ctx.body = 'Hello world';
});
app.listen(3000);

Koa Middleware

“Koa middleware are simple functions which return a MiddlewareFunction with signature (ctx, next). When the middleware is run by an "upstream" middleware, it must manually invoke next() to run the "downstream" middleware.” — Koa 2.x Guide

Koa middleware can be implemented using a stack flow which allows us to easily manage request/response flows. Our small middleware here logs the elapsed milliseconds since the request was issued:

app.use(async (ctx, next) => {
const start = new Date;
console.log(`Started at: ${start}`);
await next();
const ms = new Date - start;
console.log(`Elapsed: ${ms}ms`);
});
...app.use(async(ctx, next) => {
// Step 1
const start = new Date;
console.log(`Started at: ${start}`);
await next(); // Step 2
// Step 7
const ms = new Date - start;
console.log(`Elapsed: ${ms}ms`);
});
app.use(async(ctx, next) => {
// Step 3
console.log(`Hey, I'm just another middleware`);
await next(); // Step 4
// Step 6
console.log('More stuff after body has been set');
});
app.use(async(ctx) => {
const name = await dbCall();
// Step 5
ctx.body = `Hello ${name}`;
console.log('Body has been set');
});
...

Takeaway

Koa is an awesome, lightweight framework to develop nodejs applications that just stays out of your way. If you come from an Express background you’ll find it fundamentally different but familiar enough and refreshingly easy to understand.

Koa vs Express (https://github.com/koajs/koa/blob/master/docs/koa-vs-express.md)

ninjadevs

A group of talented developers friends located in Costa Rica.

Carlos Vega

Written by

Software engineer in love with web development. Avid reader and occasional blogger. He will blog about anything that crosses his mind. Costa Rica.

ninjadevs

ninjadevs

A group of talented developers friends located in Costa Rica.