新特性的发布
最近nodejs发布了v7.6.0。这个版本,正式包含了 async
和await
的用法,再也无需使用harmony
模式或者使用babel
转换了。
koa2
然后发现koa官方也随即更新了github上的源码。
Koa is not bundled with any middleware.
Koa requires node v7.6.0 or higher for ES2015 and async function support.
这也宣告,koa2的时代正是来临。
中间件的写法
官方文档上写着有三种
- common function
- async function
- generator function
async(node v7.6+)
app.use(async (ctx, next) => {
const start = new Date();
await next();
const ms = new Date() - start;
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
});
上面这种模式需要将node版本升级到v7.6或者更高。
common
app.use((ctx, next) => {
const start = new Date();
return next().then(() => {
const ms = new Date() - start;
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
});
});
这种模式下,无需使用async
和await
特性,只是一个普通函数。在koa2中间件里面,next()
返回的是一个promise
。
generator
app.use(co.wrap(function *(ctx, next) {
const start = new Date();
yield next();
const ms = new Date() - start;
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
}));
在koa1的时代,所有的中间件都是一个generator函数。来到koa2就不是了,当然,也可以采用generator的写法。只是需要使用一个包装器,如 co 。
平滑升级
如果原有项目是基于koa1,那么,如果想要平滑过渡到koa2而不想要改动太多,那么就需要模块koa-convert
了。具体用法
const convert = require('koa-convert');
app.use(convert(function *(next) {
const start = new Date();
yield next;
const ms = new Date() - start;
console.log(`${this.method} ${this.url} - ${ms}ms`);
}));
该模块会转化成koa2所需要的东西。
例子
既然发布了终极解决方案,那么,我也会优先并且倾向于这种写法。下面是我尝试写的一个具有参考意义但不具有实际意义的中间件。
中间件一般来说都放在另外一个文件。一来不显臃肿,而来,模块化嘛。
index.js
const Koa = require('koa');
const app = new Koa();
const time = require('./time');
app.use(async time());
// response
app.use(ctx => {
ctx.body = 'Hello Koa';
});
app.listen(3000);
time.js
function time(options) {
return function (ctx, next) {
console.time(ctx.req.url);
ctx.res.once('finish', function () {
console.timeEnd(ctx.req.url);
});
await next();
}
}
module.exports = time;
然后运行了一下,发现报错了。。。说我缺少)
为啥会错呢?难道不能将async和await拆开来写???那我改改。
index.js
app.use(time());
time.js
function time(options) {
return async function (ctx, next) {
console.time(ctx.req.url);
ctx.res.once('finish', function () {
console.timeEnd(ctx.req.url);
});
await next();
}
}
好的,大功告成。将async
关键字挪到中间件声明的地方即可。所以一个正确地中间件是这么声明的
app.use(中间件);
// 中间件:
async function (ctx, next) {
await next();
})
总结
我太年轻了,以为我想的就是别人想的。
- async和普通函数合在一起使用的。就和当初的generator一样,不能将function关键字和
*
分开。 - 这个新特性不只是在koa2才能发挥作用,在平时的express app也能使用。
- async/await:一个将异步写成同步语法的终极解决方案,解决可怕的callback hell。
再也不用 promise.then().then()....then()的丑陋写法了,直接是
let a1 = await p1();
let a1 = await p1();
.....
let an = await pn();
不错