以上5个概念应该仍是很好理解的vue
首先把koa给下载下来了,能够看到这里有四个文件,这里我主要讲下application,也就是最核心的一个模块 node
这里核心模块是application文件,从开始提及吧app
const Emitter = require("events");
class Koa2 extends Emitter {
constructor() {
super();
this.middleware = [];
this.context = Object.create(context);
this.request = Object.create(request);
this.response = Object.create(response);
}
/** * 监听listen */
listen(...args) {
}
/** * 回调函数 */
callback() {
}
/** * 使用插件 * @param {} fn */
use(fn) {
}
}
复制代码
以上咱们经常使用的是一些接口,从这些东西入手吧,这里继承了emitter这个构造函数,也就是node里面的事件监听,用过的人应该使用过下面这种koa
const app = new Koa2
app.on("error",()=>{
})
复制代码
看到这里大概就明白了为何要继承emitter,主要是为了实现事件分发async
这里很简单,其实就是把use中的函数加到中间件队列中,都应该能理解了函数
/** * 使用插件 * @param {} fn */
use(fn) {
this.middleware.push(fn);
return this;
}
复制代码
这里至关因而一个语法糖ui
/** * 监听listen */
listen(...args) {
let server = http.createServer(this.callback());
server.listen(...args);
}
/** * 回调函数 */
callback() {
const fn = conpose(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;
}
复制代码
这里将全部的中间件聚合成一个函数,这里聚合使用的是conpose,也就是koa的中间件洋葱模型this
众所周知,koa是使用async的, 这里说的,这里的dispatch至关于next的意思吧!进入spa
module.exports = function(middleware) {
return function(ctx, next) {
// let index = -1;
return dispatch(0);
function dispatch(i) {
let fn = middleware[i];
if (i === middleware.length) {
fn = next
}
if(!fn) {
return Promise.resolve()
}
try {
return Promise.resolve(fn(ctx, dispatch.bind(null, i + 1)));
} catch (error) {
return Promise.reject(error)
}
}
};
};
复制代码
再回来看callback
这个函数插件
callback() {
const fn = conpose(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, middleware) {
return middleware(ctx).then(() => {
console.log("中间件执行结束");
// 这里能够拿到中间件里面修改的数据等
/* 如ctx.response.body({ }) */
return ctx.response.res.end("hello");
});
}
/** * 建立上下文 */
createContext(req, res) {
// let ctx = {}
const context = Object.create(this.context);
context.request = Object.create(this.request);
context.response = Object.create(this.response);
context.app = this;
context.response.res = res;
context.request.req = req;
return context;
}
复制代码
req
和res
是http.createServer()的回调函数,这里就很少说了 下面的重点是建立一个上下文createContext
这里就连接到Object.create(this.context)
等, 其实也就是将context,request,response实例化,将callback里面回传的request,response重写了一下,而且提供了一些方法 Object.create(this.request)
和Object.create(this.response)
就不细说了,都是封装一些方法,封装一些返回的值
进入到context文件,咱们能够看到下面的这样一个函数调用,其实就是一个数据劫持
delegate(proto, 'response')
.method('attachment')
.method('redirect')
.method('remove')
.method('vary')
.method('set')
.method('append')
.method('flushHeaders')
.access('status')
.access('message')
.access('body')
.access('length')
.access('type')
.access('lastModified')
.access('etag')
.getter('headerSent')
.getter('writable');
复制代码
打个比方说ctx.body
,其实就是ctx.response.body
这里作了一层代理,好处的话,能够不用污染ctx,而且不须要建立两份变量,这里能够去看看vue的data是怎么作的,为何在this
中能访问到data中的变量,这里是同样的
以上就是主要的koa内容了,至于其余都是开发中间件了 最后还有一个点 就是inspect
,你看代码的时候会看到在生命对象和构造函数的时候都用到了这个inspect
举个例子哈!
const proto = {
inspect(){
return "hello inspect";
}
}
if (util.inspect.custom) {
proto[util.inspect.custom] = proto.inspect;
}
let a = Object.create(proto)
console.log(a)
// 输出 "hello inspect"
复制代码
koa里面用到,我理解的意思是,在打印的时候只打印出本身想打印出来的 ,别的不打印,其余就本身体会了。