The next part is a workshop. Please clone this Repo- https://github.com/tejasmanohar/koa-starter locally to follow along.
Completed version / Solution is here (though we may not get through all of it)- https://github.com/tejasmanohar/koa-multi
* Work through examples together
| Feature | Koa | Express |
|---|---|---|
| Middleware | ✓ | ✓ |
| Routing | ✓ | |
| Templating | ✓ | |
| Sending files | ✓ | |
| JSONP | ✓ |
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(destination + 'w'
+ width + '_' + filename, function(err) {
if (err) console.log('Error writing file: ' + err)
})
}.bind(this))
}
})
})
}
})var login
get('/token', function(err, token) {
login.token = token
if (login.token && login.key) login()
})
get('/key', function(err, key) {
login.key = key;
if (login.token && login.key) login()
})
function login() {
post('/auth', [login.token, login.key], function(err, auth) {
window.location.href = '/dashboard' + auth
})
}async.waterfall([
function(callback) {
async.parallel([
function(callback) {
get('/token', callback)
},
function(callback) {
get('/key', callback)
}
], callback)
},
function(callback) {
post('/auth', { token: result[0], key: result[1] })
}
], function() {
window.location.href = '/dashboard?' + result
})var token = get('/token')
var key = get('/key')
Promise.all([token, key]).then(function(result) {
return post('/auth') {
token: result[0],
key: result[1]
})
}).then(function(result) {
window.location.href = '/dashboard?' + result
})
function* fibonacci(){
var fn1 = 1;
var fn2 = 1;
while (true){
var current = fn2;
fn2 = fn1;
fn1 = fn1 + current;
var reset = yield current;
if (reset){
fn1 = 1;
fn2 = 1;
}
}
}
var sequence = fibonacci();
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 2
console.log(sequence.next().value); // 3
console.log(sequence.next().value); // 5
console.log(sequence.next().value); // 8
console.log(sequence.next().value); // 13
console.log(sequence.next(true).value); // 1
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 2
console.log(sequence.next().value); // 3// from callbacks
function findFriends(user, callback) {
Friend.find({ user: user }, function(err, friends) {
if (err) {
return callback(err)
}
callback(friends);
});
}
// to promises
function findFriends(user) {
return Friend.find({ user: user });
}
findFriends(user)
.then(function(friends) {
anotherAsyncOp(friends);
})
.catch(function(err) {
someHandler(err);
})
// to generators
function* findFriends(user) {
return yield Friend.find({ user: user });
}
var x = yield findFriends(user);var fs = require('co-fs');
app.use(function *(){
var paths = yield fs.readdir('docs');
var files = yield paths.map(function(path){
return fs.readFile('docs/' + path, 'utf8');
});
this.type = 'markdown';
this.body = files.join('');
});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(destination + 'w' + width + '_' + filename, function(err) {
if (err) console.log('Error writing file: ' + err)
})
}.bind(this))
}
})
})
}
})someAsyncOp().then(function() {
// ...
}).map(function(result) {
// ...
}).catch(function() {
//
}).then(function() {
// ...
}).all(function() {
// ...
});try {
yield Promise.reject(new Error('boom'));
} catch (err) {
console.error(err.message); // "boom"
}/*
App-
1. Takes input
2. Multiplies by 2
3. Returns new value
*/
function app(number) {
return number * 2;
}
app(10);
// Decorator
function decorate(multiplier) {
return function passIn(fn) {
/* Decorated fn ->
1. manipulates input
3. calls function
4. manipulates output
*/
return function decoratedFn(number) {
number++;
return multiplier * fn(number);
};
};
}decorate(2)(app)(10) // => 44
// (10 + 1) * 2 * 2 = 44
// expanded form ->
app(10) // => 20
app = decorate(2)(app)
app(10) // => 44app.use(function(req, res, next) {
var writeHead = res.writeHead
res.writeHead = function(status) {
res.writeHead = writeHead
if (status === 200) {
res.header('Content-Disposition',
'attachment; filename='
+ require('path').basename(req.url))
}
res.writeHead.apply(res, arguments)
}
next()
})function responseTime(options) {
var opts = options || {}
if (typeof options === 'number') {
deprecate('number argument: use {digits: '
+ JSON.stringify(options) + '} instead')
opts = { digits: options }
}
var fn = typeof opts !== 'function'
? createSetHeader(opts)
: opts
return function responseTime(req, res, next) {
var startAt = process.hrtime()
onHeaders(res, function onHeaders() {
var diff = process.hrtime(startAt)
var time = diff[0] * 1e3 + diff[1] * 1e-6
fn(req, res, time)
})
next()
}
}
function createSetHeader(options) {
var digits = options.digits !== undefined
? options.digits
: 3
var header = options.header || 'X-Response-Time'
var suffix = options.suffix !== undefined
? Boolean(options.suffix)
: true
return function setResponseHeader(req, res, time) {
if (res.getHeader(header)) return
var val = time.toFixed(digits)
if (suffix) val += 'ms'
res.setHeader(header, val)
}
}var end = res.end;
res.end = function(data, encoding){
res.end = end;
if (!req.session) return res.end(data, encoding);
req.session.resetMaxAge();
if (resaveSession || isModified(req.session)) {
debug('saving');
return req.session.save(function(err){
if (err) console.error(err.stack);
debug('saved');
res.end(data, encoding);
});
}
res.end(data, encoding);
};function responseTime() {
return function *responseTime(next){
var start = Date.now();
yield* next;
var delta = Math.ceil(Date.now() - start);
this.set('X-Response-Time', delta + 'ms');
}
}function *random(next) {
if ('/random' == this.path) {
this.body = Math.floor(Math.random()*10);
} else {
yield next;
}
};
function *backwards(next) {
if ('/backwards' == this.path) {
this.body = 'sdrawkcab';
} else {
yield next;
}
}
function *pi(next) {
if ('/pi' == this.path) {
this.body = String(Math.PI);
} else {
yield next;
}
}
function *all(next) {
yield random.call(this,
backwards.call(this,
pi.call(this, next)));
}
app.use(all);app.use(compose([random, backwards, pi]))A Koa application is an object containing an array of middleware generator functions which are composed and executed in a stack-like manner upon request
app.use(function *(){
this.body = 'Hello World';
});
app.use(function *(){
this; // context
this.request; // koa request
this.response; // koa response
this.req; // node.js request
this.res; // node.js response
});// express
var express = require('express');
var app = express();
app.get('/', function(req, res){
res.send('hello world');
});
// koa
var koa = require('koa');
var app = koa();
app.use(function *() {
if (url === '/') this.body = 'Hello World';
});
// koa-route
var koa = require('koa');
var app = koa();
var route = require('koa-route');
app.use(route.get('/', function *() {}
this.body = 'Hello World';
));$ DEBUG=koa* node examples/simple
koa:application use responseTime +0ms
koa:application use logger +4ms
koa:application use contentLength +0ms
koa:application use notfound +0ms
koa:application use response +0ms
koa:application listen +0msvar path = require('path');
var static = require('koa-static');
var publicFiles = static(path.join(__dirname, 'public'));
publicFiles._name = 'static /public';
app.use(publicFiles);function Person() {
var self = this;
self.age = 0;
setInterval(function growUp() {
self.age++;
}, 1000);
}function Person() {
setInterval(function growUp() {
this.age++;
}.bind(this), 1000);
}function Person(){
this.age = 0;
setInterval(() => {
this.age++;
}, 1000);
}
var p = new Person();(param1, param2, paramN) => { statements }
(param1, param2, paramN) => expression
singleParam => { statements }
singleParam => expression
() => { statements }
params => ({foo: bar})class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise.');
}
}
class Dog extends Animal {
speak() {
console.log(this.name + ' barks.');
}
}var obj = {
// __proto__
__proto__: theProtoObj,
// Does not set internal prototype
'__proto__': somethingElse,
// Shorthand for ‘handler: handler’
handler,
// Methods
toString() {
// Super calls
return "d " + super.toString();
},
// Computed (dynamic) property names
[ "prop_" + (() => 42)() ]: 42
};// list matching
var [a, , b] = [1,2,3];
// object matching
var { op: a, lhs: { op: b }, rhs: c }
= getASTNode()
// object matching shorthand
// binds `op`, `lhs` and `rhs` in scope
var {op, lhs, rhs} = getASTNode()
// Can be used in parameter position
function g({name: x}) {
console.log(x);
}
g({name: 5})
// Fail-soft destructuring
var [a] = [];
a === undefined;
// Fail-soft destructuring with defaults
var [a = 1] = [];
a === 1;// Basic literal string creation
`This is a pretty little template string.`
// Multiline strings
`In ES5 this is
not legal.`
// Interpolate variable bindings
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`
// Unescaped template strings
String.raw`In ES5 "\n" is a line-feed.`function f(x, y=12) {
return x + y;
}
f(3) == 15 // => truefunction f(x, ...y) {
// y is an Array
return x * y.length;
}
f(3, "hello", true) == 6function f(x, y, z) {
return x + y + z;
}
f(...[1,2,3]) == 6 // => truefunction f() {
{
let x;
{
// okay, block scoped name
const x = "sneaky";
// error, const
x = "foo";
const obj = { hi: 2 };
// valid
obj.hi = 3;
}
// okay, declared with `let`
x = "bar";
// error, already declared in block
let x = "inner";
}
}for (var n of fibonacci) {
// truncate the sequence at 1000
if (n > 1000)
break;
console.log(n);
}// same as ES5.1
"𠮷".length == 2
// new RegExp behaviour, opt-in ‘u’
"𠮷".match(/./u)[0].length == 2
// new form
"\u{20BB7}" == "𠮷" == "\uD842\uDFB7"
// new String ops
"𠮷".codePointAt(0) == 0x20BB7
// for-of iterates code points
for(var c of "𠮷") {
console.log(c);
}// lib/math.js
export function sum(x, y) {
return x + y;
}
export var pi = 3.141593;
// app.js
import * as math from "lib/math";
alert("2π = " + math.sum(math.pi, math.pi));
// otherApp.js
import {sum, pi} from "lib/math";
alert("2π = " + sum(pi, pi));// Sets
var s = new Set();
s.add("hello")
.add("goodbye")
.add("hello");
s.size === 2;
s.has("hello") === true;
// Maps
var m = new Map();
m.set("hello", 42);
m.set(s, 34);
m.get(s) == 34;
// Weak Maps
var wm = new WeakMap();
wm.set(s, { extra: 42 });
wm.size === undefined
// Weak Sets
var ws = new WeakSet();
ws.add({ data: 42 });(function() {
// module scoped symbol
var key = Symbol("key");
function MyClass(privateData) {
this[key] = privateData;
}
MyClass.prototype = {
doStuff: function() {
... this[key] ...
}
};
typeof key === "symbol"
})();
var c = new MyClass("hello")
c["key"] === undefined// User code of Array subclass
class MyArray extends Array {
constructor(...args) { super(...args); }
}
var arr = new MyArray();
arr[1] = 12;
arr.length == 2Number.EPSILON
Number.isInteger(Infinity) // false
Number.isNaN("NaN") // false
Math.acosh(3) // 1.762747174039086
Math.hypot(3, 4) // 5
Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2) // 2
0b111110111 === 503 // true
0o767 === 503 // true
"abcde".includes("cd") // true
"abc".repeat(3) // "abcabcabc"
Array.from(document.querySelectorAll("*")) // Returns a real Array
Array.of(1, 2, 3)
[0, 0, 0].fill(7, 1) // [0,7,7]
[1,2,3].findIndex(x => x == 2) // 1
["a", "b", "c"].entries() // iterator [0, "a"], [1,"b"], [2,"c"]
["a", "b", "c"].keys() // iterator 0, 1, 2
["a", "b", "c"].values() // iterator "a", "b", "c"
Object.assign(Point, { origin: new Point(0,0) })function factorial(n, acc = 1) {
"use strict";
if (n <= 1) return acc;
return factorial(n - 1, n * acc);
}
factorial(100000)