简介:

Koa2是基于node实现的web框架,特点是优雅,简洁,表达力强,自由度高。相比express相比更轻量。

跟1.0的区别:

koa1.0使用的是generator+co.js的执行方式,而2.0采用的是async/await,因此使用2.0的话需要运行在node 8版本及以上,如果当前的版本太低的话,可以进行版本的升级或者安装babel-cli,用其中的babel-node来运行。

实现koa2的四大模块:

四大模块分别是:

1.封装node http server,创建Koa类构造函数

2.构造request,reponse,context对象

3.中间件机制和剥洋葱模型的实现

4.错误机制和错误处理

模块一:

通过koa2源码可以知道,实现koa的服务器应用和端口监听是基于node代码进行了封装。

let http = require('http');
let server = http.createServer((req, res) => {
res.writeHead(200);
res.end('hello world');});
server.listen(3000, () =>{
console.log('listenning on 3000');
});

将上面的node原生代码封装成koa模式:

const  http=require('http');
const  Koa=require('koa');
const app=new Koa();
app.listen(3000);

模块二:

通过阅读源码可以知道,lib文件夹下放着四个koa2的核心文件中的context.js,request.js,reponse.js分别对应request,reponse,context三个模块的代码文件。context是ctx,相当于一个全局koa实例上下文this,连接request,reponse两个功能模块,并且暴露给koa的实例和中间件等回调函数的参数中。

request和reponse两个模块分别对node的原生request和reponse进行了封装,例如

request.js模块:

let url = require('url');
module.exports = {get query() {
return url.parse(this.req.url, true).query;
}};

当在koa实例中使用ctx.query时,相当于返回url.parse(this.req,true).query的值。此外,还封装了header,url,origin,path等方法,都是对原生request上用getter和setter进行了进一步的封装。

response.js模块:

module.exports = {get body() {
return this._body;
},
set body(data) {
this._body = data;
},
get status() {
return this.res.statusCode;
},
set status(statusCode) {
if (typeof statusCode !== 'number') {
throw new Error('something wrong!');
}
this.res.statusCode = statusCode;
}};

上面是对koa的status的读取和设置,读取的时候是基于原生的statusCode属性。

context.js模块:

上面已经大概介绍了一下context的作用,是连接request,reponse两个功能模块,及将request,response对象挂载到ctx的上面,从而可以让koa的实例使用request,response对象中的方法。

let proto = {};
function delegateSet(property, name) {
proto.__defineSetter__(name, function (val) {
this[property][name] = val;
});
}
function delegateGet(property, name) {
proto.__defineGetter__(name, function () {
return this[property][name];
});
}
let requestSet = [];
let requestGet = ['query'];
let responseSet = ['body', 'status'];
let responseGet = responseSet;requestSet.forEach(ele  =>; {
delegateSet('request', ele);
});
requestGet.forEach(ele =>; {
delegateGet('request', ele);
});
responseSet.forEach(ele  =>; {
delegateSet('response', ele);
});
responseGet.forEach(ele  =>; {
delegateGet('response', ele);
});
module.exports = proto;

下面将req,res所有方法挂在到context下,修改application.js文件

let http = require('http');
let context = require('./context');
let request = require('./request');
let response = require('./response');
createContext(req, res) {
let ctx = Object.create(this.context);
ctx.request = Object.create(this.request);
ctx.response = Object.create(this.response);
ctx.req = ctx.request.req = req;
ctx.res = ctx.response.res = res;
return ctx;
}

我们生成了createContext这个方法,首先,它通过Object.create创建ctx,并将req和res挂在到新创建的ctx上。

模块三:

koa的中间件模型是一个剥洋葱模型,多个中间件通过use放在一个数组队列然后从外层开始执行,遇到next后进入队列中的下一个中间件,所有的中间件开始回帧,执行队列中之前中间件中未执行的代码部分,这就是剥洋葱模型。

例子:

let Koa = require('../src/application');
let app = new Koa();
app.use(async (ctx, next) => {
console.log(1);
await next();
console.log(6);
});
app.use(async (ctx, next) => {
console.log(2);
await next();console.log(5);
});
app.use(async (ctx, next) =>; {
console.log(3);
ctx.body = "hello world";console.log(4);
});
app.listen(3000, () =>; {
console.log('listenning on 3000');
});
根据上面的剥洋葱模型,以上代码的执行顺序应该是123456。
中间件模块的实现代码:
compose() {
return async ctx => {
function createNext(middleware, oldNext) {
return async () => {
await middleware(ctx, oldNext);
}}
let len = this.middlewares.length;
let next = async () => {
return Promise.resolve();
};
for (let i = len - 1; i >= 0; i--) {
let currentMiddleware = this.middlewares[i];
//将上一个中间件的next当做参数传给下一个中间件
next = createNext(currentMiddleware, next);
}
await next();};}callback() {
return (req, res) => {
let ctx = this.createContext(req, res);
let respond = () => this.responseBody(ctx);
let onerror = (err) =>;
this.onerror(err, ctx);
let fn = this.compose();return fn(ctx);
};}

主要流程是通过use传进来的中间件是一个回调函数回调函数的参数是ctx上下文和next,next的作用是停止当前中间件,执行下一个中间件next()之前的代码,在下一个中间件运行的代码遇到next(),又会将执行权交给下下中间件。

模块四:

该模块主要是在运行过程中发生错误的时候可以捕获错误和抛出异常,并将该错误信息进行反馈。

中间件错误捕获:
return fn(ctx).then(respond).catch(onerror);
框架层面异常捕获:
let EventEmitter = require('events');
//koa构造函数继承events模块
class Application extends EventEmitter {}
let app = new Koa();
//on监听函数
app.on('error', err => {
console.log('error happends: ', err.stack);
});

Koa2框架的原理解析和实现相关推荐

  1. 阿里分布式事务框架Seata原理解析

    阿里分布式事务框架Seata原理解析 作者:伊凡的一天 链接:https://www.jianshu.com/p/044e95223a17 Seata框架是一个业务层的XA(两阶段提交)解决方案.在理 ...

  2. netty框架及原理解析

    本篇首发于橙寂博客转载请加上此标示. 正式开始了netty的学习,netty是基于nio上的一个框架.期间翻阅了很多文档以及资料.先推荐给大家. 相关文档 Netty源码在线阅读: Netty-4.1 ...

  3. AOP框架Aspects原理解析

    先说下我的读源码过程 , 总计花了1天时间 , 早上还是一脸懵 , 下午就是成竹在胸了 1 .先看了这2篇文章 , 知道了大体的思路, 找到了源码的骨头架子, https://www.jianshu. ...

  4. 分布式服务框架dubbo原理解析 转

    alibaba有好几个分布式框架,主要有:进行远程调用(类似于RMI的这种远程调用)的(dubbo.hsf),jms消息服务(napoli.notify),KV数据库(tair)等.这个框架/工具/产 ...

  5. 分布式事务seata只支持MySQL_阿里分布式事务框架Seata原理解析

    Seata框架是一个业务层的XA(两阶段提交)解决方案.在理解Seata分布式事务机制前,我们先回顾一下数据库层面的XA方案. 1. MySQL XA方案 MySQL从5.7开始加入了分布式事务的支持 ...

  6. 微信小程序框架探究和解析

    2019独角兽企业重金招聘Python工程师标准>>> 何为框架 你对微信小程序的技术框架了解多少? 对wepy 框架进行一系列的深入了解 微信小程序框架解析和探究 小程序组件化框架 ...

  7. php 框架源码分析,Laravel框架源码解析之模型Model原理与用法解析

    本文实例讲述了Laravel框架源码解析之模型Model原理与用法.分享给大家供大家参考,具体如下: 前言 提前预祝猿人们国庆快乐,吃好.喝好.玩好,我会在电视上看着你们. 根据单一责任开发原则来讲, ...

  8. 内存泄漏分析框架LeakCanary的使用与原理解析

    文章目录 1. 常见内存泄漏 1.1 "单例模式" 造成的内存泄漏 1.2 "静态实例" 造成内存泄漏 1.3 "Handler" 造成的内 ...

  9. 事件总线框架EventBus的使用与原理解析

    文章目录 1. EventBus框架 1.1 EventBus简介 1.2 EventBus基本使用 1.2.1 添加Gradle依赖 1.2.2 定义事件 1.2.3 准备订阅者 1.2.4 发布事 ...

最新文章

  1. Syslog-ng+Rsyslog收集日志:logrotate日志切割、轮询(七)
  2. Java集合,ConcurrentHashMap底层实现和原理(常用于并发编程)
  3. 【转载+软件实际操作 OpenHW12参赛手记】ZedBoard-裸机下运行Hello,World【常见错误解决方案】++...
  4. 微信小程序 提示Toast
  5. jq点击按钮打开和关闭弹出层,点击除了当前按钮以外的地方关闭弹出层
  6. PHP json_encode不转义中文
  7. netbeans下开发rails快捷键 及 Ruby On Rails开发技巧总结
  8. ArcGIS 代理产品价格以及折扣表、产品描述
  9. 过拟合怎么产生的?防治措施?
  10. vue+node全栈移动商城【6】-node接口配置文件
  11. 2018司法人工智能:罪名预测、刑期预测、法条推荐
  12. 14. model(2)
  13. 提高页面渲染速度的建议以及方案
  14. 【总结】Unity游戏优化
  15. 条码标签打印软件如何设置圆形标签
  16. ASU计算机科学专业大学排名,2013美国大学排名_计算机科学专业研究生排名
  17. 最近抖音上虚拟元宇宙项目-猜歌名,代码解析
  18. 红黑树 插入算法(一)
  19. Python turtle库的应用实例——画大白(情人节表白神器)
  20. js删除网页中图片width 和 height

热门文章

  1. 思科交换机实现管理口访问设置+远程登录(一)
  2. 网站绑定域名后不能用IP直接访问了?
  3. miui v5 android版本,速度明显提升 小米2S刷安卓4.4版MIUI V5
  4. shell屏蔽错误和警告输出
  5. JavaScript经典进阶:javascript – 9宫格 – 拼图
  6. 503 Service Unavailable 异常是什么情况导致的。
  7. MAC下安装GDAL库
  8. 报!!第十二届蓝桥杯大赛报名启动!!
  9. 第十二届蓝桥杯大赛软件赛省赛第二场题解
  10. Mapper method ‘com.example.democrud.democurd.usermapper.DaoMapper.addOnce‘ has an unsupported return