洋葱模型php,koa 洋葱模型

分析

1、首先这是koa2最简单的入门例子,我将通过这个入门例子来演示koa2的洋葱模型

const Koa = require('koa');

const app = new Koa();

app.use((ctx,next)=>{

console.log("第一个中间件执行");

next() ;

});

// 第二个中间件

app.use((ctx,next)=>{

console.log("第二个中间件");

})

let r = app.listen(8080);

console.log("server run on 8080");

在这里面,app首先是调用了两次use,然后就开始监听端口,

listen(...args) {

debug('listen');

// 当客户端发送请求将会调用callback

const server = http.createServer(this.callback());

return server.listen(...args);

}

因此use是核心:

use(fn) {

// ... 一些判断代码

this.middleware.push(fn);

return this;

}

从上面可以看出这里将外部use的函数通过内部的一个middleware变量记录下来,然后就没了。

OK,现在当客户端发送请求的时候,内部会创建上下文对象,然后处理请求:

callback() {

const fn = compose(this.middleware);

if (!this.listenerCount('error')) this.on('error', this.onerror);

const handleRequest = (req, res) => {

// 创建上下文

const ctx = this.createContext(req, res);

// 处理请求

return this.handleRequest(ctx, fn);

};

return handleRequest;

}

处理请求

handleRequest(ctx, fnMiddleware) {

const res = ctx.res;

res.statusCode = 404;

const onerror = err => ctx.onerror(err);

const handleResponse = () => respond(ctx);

onFinished(res, onerror);

// 核心,调用中间件,从这里可以看出我们use(fn)中的fn是一个promise

return fnMiddleware(ctx).then(handleResponse).catch(onerror);

}

OK,到这里我们知道当浏览器发送一个请求的时候,koa的application对象会根据middleware调用compose来生成一个另一个函数fn,然后向fn中传入上下文ctx执行这个函数。我们都知道,最上面的代码执行顺序是先打印第一个中间件执行,再打印第二个中间件执行,那么这个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)

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)

}

}

}

}

上面代码虽然不多,但是是koa2实现洋葱模型最重要的部分。整个过程如下:

客户端发送请求,调用fn(ctx),此时next为空=>dispatcher(0),获取第一次use的函数(middleware[0])执行这个函数,参数为:ctx、dispatch(1),这个dispatcher(1),也就是第一次use中的next;执行next();

在第一次use中的方法体中执行next()等价于执行dispatcher(1),此时获取第二次use的函数(middleware[1]),接着再执行这个函数,参数为:ctx、dispatch(2),以此类推执行后面的中间件.

总结

koa2源码虽然少,但是原理巧妙,值得学习,也正是因为它的小,对于w我们看源码学习也能更轻松.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值