解析koa源码

首相,讲解一下koa的大致思路,用户实例化Koa构造函数,通过调用实例化对象上的use方法,获取到url地址等属性,也可以通过body给客户端响应内容,这些属性都是集成在ctx对象上。用户通过调用listen方法开启服务配置端口号。我们来看一下koa到底是怎么配置一个服务的。

const Koa = require("./koa/application.js");   // 自定koa函数
const app = new Koa();
app.use(async function(ctx,next){
    console.log(ctx.url);
    console.log(ctx.request.path);
    await next();
    ctx.body = "hello world";
})
app.use(async function(ctx,next){
    await log();   // 异步promise对象
    await next();
    console.log(3333);
})
app.use(function(ctx,next){
    console.log(4444);
    next();
    console.log(5555);
})
app.listen(8888,function(){
    console.log("localhost:8888")
})

准备主体文件application.js

1、koa是通过package.json设置默认引用主体文件,主体文件会准备一个Koa构造函数,函数内准备一个存储器,当用户执行use时,用来存储use里面的回调函数。当用户执行listen的时候,通过http模块开启服务。

const http = require("http");
function Koa(){
    this.callback = []
}
Koa.prototype.use = function(fn){
    this.callback.push(fn);
}
Koa.prototype.listen = function(){
    const server = http.createServer(this.server.bind(this));
    server.listen(...arguments);
}

2、通过server函数集成ctx对象,http模块会默认传递req和res对象,我们需要把req/res集成到ctx对象上,这里注意的是ctx对象的req/res是等于http服务上的req/res。还需要准备三个js文件用来存储ctx/request/response这三个对象。

const context = require("./context.js");
const request = require("./request.js");
const response = require("./response.js");
Koa.prototype.getCtx = function(req,res){
    let ctx = Object.create(context);
    ctx.request = Object.create(request);
    ctx.response = Object.create(response);
    ctx.req = ctx.request.req = req;
    ctx.res = ctx.response.res = res;
    return ctx;
}
Koa.prototype.server = async function(req,res){
    let ctx = this.getCtx(req,res);
}

3、处理用户调用use储存在callback的回调函数,默认会执行第一次回调函数,当用户执行next的时候,我们需要准备一个执行机传递给next作为回调函数的参数,执行机的内容也就是执行下一个use。

Koa.prototype.compose = function(ctx,callback){
    function dispath(index){
        if(index == callback.length) return;
        let exe = callback[index];
        return Promise.resolve(exe(ctx,()=>dispath(index+1)));
    }
    return dispath(0)
}
Koa.prototype.server = async function(req,res){
    ........
    await this.compose(ctx,this.callback);
}

4、监听ctx.body里面的内容,当用户body有设置值的时候,通过end把值响应给客户端,没有值需要给个默认的code和值。

Koa.prototype.server = async function(req,res){
    ........
    let content = "";
    if(ctx.body){
        content = ctx.body;
    }else{
        res.statusCode = 404;
        content = "Not Found";
    }
    res.end(content);
}

准备request.js文件作为ctx.request对象进行拦截

const url = require("url");
let request = {
    get url(){
        return this.req.url;
    },
    get path(){
        return url.parse(this.req.url).pathname;
    }
}
module.exports = request;

准备response.js文件作为ctx.response对象进行拦截

let response = {
    get body(){
        return this._body;
    },
    set body(newValue){
        this._body = newValue;
    }
}
module.exports = response;

准备context.js文件作为ctx对象进行拦截

let context = {}
function intercept(property,name){
    Object.defineProperty(context,name,{
        get(){
            return this[property][name];
        },
        set(newValue){
            this[property][name] = newValue;
        }
    })
}
intercept("request","url");
intercept("request","path");
intercept("response","body");
module.exports = context;

项目案例

你可能感兴趣的:(解析koa源码)