koa的处理流程
![](https://img.haomeiwen.com/i11434708/5ec5cf8a60699372.png)
koa的中间件
const Koa = require('koa');
const app = new Koa();
// logger
app.use(async (ctx, next) => {
await next();// 将控制权交给下一个中间件
const rt = ctx.response.get('X-Response-Time');
console.log(`${ctx.method} ${ctx.url} - ${rt}`);
});
// x-response-time
app.use(async (ctx, next) => {
const start = Date.now();
await next();// 将控制权交给下一个中间件
const ms = Date.now() - start;
ctx.set('X-Response-Time', `${ms}ms`);
});
// response
app.use(async ctx => {
ctx.body = 'Hello World';
});
app.listen(3000);
洋葱模型实现
- 通过
await next();
进入下一个中间件 -
next
是compose
中定义的dispatch
关键代码 compose
的实现
function compose (middleware) {
if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')
for (const fn of middleware) {
if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!')
}
/**
* @param {Object} context
* @return {Promise}
* @api public
*/
return function (context, next) {
// last called middleware #
let index = -1
return dispatch(0)
// dispatch 就是包装我们的中间件
function dispatch (i) {
if (i <= index) return Promise.reject(new Error('next() called multiple times'))
index = i
let fn = middleware[i]
if (i === middleware.length) fn = next
if (!fn) return Promise.resolve()
try {
// 这里是执行我们添加的每一个中间件的时机
// 并且next 就是dispatch
return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
} catch (err) {
return Promise.reject(err)
}
}
}
}
最终我们开始部分的代码中间件执行顺序如下(伪代码)
// middlewares
一个请求达到之后
执行中间件 fn0(ctx, next)
fn0 --->
前半段
await next()---> 交出控制权(通过generator实现的协程实现),执行fn1
fn1 --->
前半段
await next()---> 交出控制权(通过generator实现的协程实现),执行fn2
fn2 --->
前半段
后半段
恢复控制权---> fn1
await next()---> 交出控制权(通过generator实现的协程实现),执行fn2
----> 恢复(上面的await 赋值操作也会执行)
后半段
恢复控制权---> fn2
await next()---> 交出控制权(通过generator实现的协程实现),执行fn2
----> 恢复(上面的await 赋值操作也会执行)
后半段
这就是
![](https://img.haomeiwen.com/i11434708/fa74290caaad3cd8.png)
既然compose
如此重要,先看下javascript
中的compose
compose 函数式编程中一个重要的使用
通过组合不同的功能达到最终的实现。
-
问题
-
代码实现
// undercore中的实现
_.compose = function() {
var args = arguments;
var start = args.length - 1;
// 返回一个函数
return function() {
var i = start;
// 从后向前执行 每一个函数,并且将返回值记录
var result = args[start].apply(this, arguments);
while (i--) result = args[i].call(this, result);
return result;
};
};
- 作用
(1)分解任务
(2)函数式编程中的复用和扩展性的实现
(3)数据流管道
函数柯里化 curry
-
问题
-
解决 (curry实现)
function curry(fn, length) {
let args = [];
length = length|| fn.length;
return function inner(...arg) {
args = args.concat(arg);
if(length) {
if(args.length<length) {
// console.log('inner');
return inner;
} else {
return fn.apply(null, args)
}
}
}
}
- 作用
(1)参数预设(缓存)
(2)延时函数执行时机
(3)分解任务
(4)将多参数版本改成单参数版本 供compose
消费
参考:
网友评论