# koa 洋葱模型
当我们调用 app.use()会push 中间件到中间件数组,
当我们调用 app.listen()的时候,内部会调用this.callback()
this.callback又调用了compose函数,将中间件进行组合,
当遇到路由的时候,会调用 handleRequest函数,该函数调用 compose函数返回的函数,
该函数(调用 compose函数返回的函数)通过递归的方式,调用中间件。
执行第一个中间件的时候,通过递归的方式将下个中间件传入,当我们调用await next()的时候,会进入下一个中间件, 当最后一个中间件调用 return Promise.resolve(199) 的时候回跳出当前中间件,回到上一个中间件 这就是洋葱模型
# 应用demo
const koa = require('koa')
const Router = require('koa-router')
const app = new koa()
const router = Router()
app.use(async (ctx, next) => {
console.log('diyige')
// console.log('start')
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) => {
console.log('dierge')
// const start = Date.now();`
await next();
// const ms = Date.now() - start;
// ctx.set('X-Response-Time', `${ms}ms`);
});
function sleep(){
return new Promise((resolve) =>{
setTimeout(() => {
resolve('ok')
}, 3000);
})
}
router.get('/', async(ctx, next) => {
const res = await sleep()
ctx.body = res
})
app.use(router.routes())
app.listen(3000)
console.log('server listening at port 3000')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# 代码翻译
var middleware = [async function(ctx,next){
console.log(1)
await next()
console.log(5)
return ctx
},async function(ctx,next){
console.log(2)
await next()
console.log(4)
return ctx
},async function(ctx,next){
await next()
return ctx
},async function(ctx,next){
ctx.body = {
msg:'请求成功',
code: 200
}
}];
var context ={
name:1,
age:2
}
function compose (middleware) {
return function (context, next) {
// last called middleware #
let index = -1
return dispatch(0)
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 {
return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
} catch (err) {
return Promise.reject(err)
}
}
}
}
const fnMiddleware = compose(middleware);
fnMiddleware(context).then(res =>{
console.log('res :', res);
})
// fnMiddleware 执行后 展开形式如下
function fnMiddleware(ctx){
return Promise.resolve((async function(ctx){
console.log(1)
await Promise.resolve((async function(ctx){
console.log(2)
await Promise.resolve((async function(ctx){
console.log(3)
return Promise.resolve(199)
})())
console.log(4)
})())
console.log(5)
})())
}
fnMiddleware({}).then(res =>{
console.log('res',res)
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69