这是我参与更文挑战的第14天,活动详情查看:更文挑战
介绍
koa-convart 是用于兼容 koa1 与 koa2 的一个工具库。koa 0.x 以及 1.x 版本的中间件是 generator 函数形式,而 koa 2.x 的中间件是 promise 的形式。通过以下代码对比一下:
// koa 1.x 示例
var koa = require('koa');
var app = koa();
app.use(function *(next){
var start = new Date;
yield next;
//再次进入中间件,记录2次通过此中间件「穿越」的时间
var ms = new Date - start;
this.set('X-Response-Time', ms + 'ms');
});
app.use(function *(){
this.body = 'Hello World';
});
app.listen(3000);
//=================================================
// koa 2.x 示例
const Koa = require('koa');
const app = new Koa();
app.use(async (ctx, next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;
ctx.set('X-Response-Time', `${ms}ms`);
});
app.use(async ctx => {
ctx.body = 'Hello World';
});
app.listen(3000);
复制代码
通过对比可以看到,旧版本的中间件是 generator 函数,接受一个 next 方法,而新版本的中间件则是以async 函数(本质是一个promise),接受两个参数:上下文 ctx 和 next 方法。
koa-convert所实现的功能就是,使 koa2 能够兼容旧版的中间件,或者使 koa1 能够使用新版的中间件,另外还提供了组合新老中间件的 api。使用示例如下:
const Koa = require('koa') // koa v2.x
const convert = require('koa-convert')
const app = new Koa()
app.use(modernMiddleware)
app.use(convert(legacyMiddleware))
app.use(convert.compose(legacyMiddleware, modernMiddleware))
function * legacyMiddleware (next) {
// before
yield next
// after
}
function modernMiddleware (ctx, next) {
// before
return next().then(() => {
// after
})
}
复制代码
源码分析
koa-convert 源码代码量很少,包括注释和空行总共 105 行,核心代码只有几十行,包括三个 api方法:convert()、convert.compose、convert.back。
convert
我们先来看convert()的源码实现,逻辑如下:
convert方法首先判断传入的中间件是否是一个函数,如果不是就抛出异常;- 接着判断是否是一个
generator函数,如果不是就直接返回不做处理; - 利用
co将generator函数形式的中间件转成promise形式。
co相关知识,可以翻阅我写的源码系列—co进行过学习。
function convert (mw) {
// 不是函数抛出异常
if (typeof mw !== 'function') {
throw new TypeError('middleware must be a function')
}
// 不是 generator 函数,直接返回
if (
mw.constructor.name !== 'GeneratorFunction' &&
mw.constructor.name !== 'AsyncGeneratorFunction'
) {
return mw
}
// 通过 co 进行转换
const converted = function (ctx, next) {
return co.call(
ctx,
mw.call(
ctx,
(function * (next) { return yield next() })(next) // 返回下一个中间件并作为参数传入
))
}
converted._name = mw._name || mw.name
return converted
}
复制代码
convert.compose
接着来看 convert.compose 的实现。
convert.compose 用于将多个中间件合成一个中间件,其中使用了 koa-compose 工具库,该工具库用于将多个中间件进行洋葱模型的组合,详细知识可以通过我写的这篇源码系列—koa-compose进行学习了解。
convert.compose = function (arr) {
// 首先判断入参形式,接受一个数组或者是多个参数
// convert.compose(mw, mw, mw)
// convert.compose([mw, mw, mw])
if (!Array.isArray(arr)) {
// 如果是多个参数就通过 Array.from 转成数组
arr = Array.from(arguments)
}
// 将数组的每一项都通过 convert 转换成 promise 形式的中间件
// 然后调用 compose 进行洋葱模型组合
return compose(arr.map(convert))
}
复制代码
convert.back
最后看一下 convert.back的实现。
convert.back 用于将 promise 中间件转换成 generator 函数形式的中间件,使 koa2 的中间件能够在 koa1 中使用。源码逻辑如下:
- 判断是否是函数,不是函数就抛出错误异常;
- 判断是否是 generator 函数,是则直接返回;
- 将
mw包装成一个generator函数,使用co将generator函数形式的next转成promise传给mw。
convert.back = function (mw) {
if (typeof mw !== 'function') {
throw new TypeError('middleware must be a function')
}
if (mw.constructor.name === 'GeneratorFunction' || mw.constructor.name === 'AsyncGeneratorFunction') {
return mw
}
// 用 generator 函数对中间件进行封装
const converted = function * (next) {
const ctx = this
let called = false // 用于判断 next 是否被调用了两次
yield mw(ctx, function () {
if (called) {
throw new Error('next() called multiple times')
}
called = true
// mw 是 promise 中间件,接收的 next 也是 promise
// 此时传递进来的 next 是 generator,需要用 co 转换一下
return co.call(ctx, next)
})
}
converted._name = mw._name || mw.name
return converted
}
复制代码
相关资料
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END





















![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)
![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)
