超级详细的koa源码解析(看完不会我打你)

如果你想提升node水平,那么我极力推荐你看看koa源码

koa作者是神一般的男人TJ Holowaychuk,源码设计巧妙而又短小精悍,既能领略koa的设计思想,而又避免了源码过冗长而带来的疲劳感。

这篇文章,我们从源头出发,一起领略kao的精髓,同时围绕下面三点介绍:

1.老生常谈的 洋葱模型
2. context的 委托模式
3. koa的 错误处理


目录结构

话不多说,让我们开始吧~首先请跟我一起打开命令行 输入

touch koa_learn.js && npm init && npm i koa

然后用任何一个ide打开koa_learn.js,我们看看node_modules下的koa目录结构。
在这里插入图片描述
除了readme、历史信息、开源许可证,真正的源码部分只有四个文件。application、context、request、response。 打开package.json文件,我们可以看到koa的入口。

  "main": "lib/application.js",
application.js

好的,让我们开始写一个简单的Demo。

const Koa = require("koa");
const app = new Koa();

app.use(async (ctx, next) => {
   
  ctx.body = "你好,YouHe";
});

app.listen(3000);

然后在终端上

curl http://localhost:3000
//终端上打印出 *你好,YouHe*

我们看到,app.js里引入了koa,然后用new来实例化一个app,之后我们使用了app.use传入一个async函数,也就是kao中间件,最后调用app.listen方法,至此一个kao应用就跑起来了。

打开application.js文件,首先看到这里暴露了一个Application类,继承于Emitter(错误处理讲到)。

constructor
module.exports = class Application extends Emitter {
   

  constructor(options) {
   
    super();
    options = options || {
   };  //配置
    this.proxy = options.proxy || false;   //是否proxy模式
    this.subdomainOffset = options.subdomainOffset || 2;  //domain要忽略的偏移量
    this.proxyIpHeader = options.proxyIpHeader || 'X-Forwarded-For'; //proxy自定义头部
    this.maxIpsCount = options.maxIpsCount || 0;  //代理服务器数量
    this.env = options.env || process.env.NODE_ENV || 'development';  //环境变量
    if (options.keys) this.keys = options.keys;   // 自定义cookie 密钥
    this.middleware = [];  //中间件数组
    this.context = Object.create(context);
    this.request = Object.create(request);
    this.response = Object.create(response);
    
    if (util.inspect.custom) {
      //自定义检查,这里的作用是get app时,去执行this.inspect 。感兴趣可见http://nodejs.cn/api/util.html#util_util_inspect_custom
      this[util.inspect.custom] = this.inspect;
    }
  }
...

这里是constructor里做了一些配置,这里主要是

    this.middleware = [];  //中间件数组
    this.context = Object.create(context);
    this.request = Object.create(request);
    this.response = Object.create(response);

首先是一个中间件数组,我们用use使用的中间件都会放进这个数组中,然后分别用Object.create拷贝的context、request、response,分别对应koa目录的三个文件。这里用Object.create是因为我们在同一个应用中可能会有多个new Koa的app,为了防止这些app相互污染,用拷贝的方法让其引用不指向同一个地址。

app.use

在这里插入图片描述

这里首先判断use传进来的参数是不是一个函数,然后判断函数是否为generator函数,并将其转化为generator,这里用到了convert函数,本质上其实是用到co去把generator转成了一个返回promise的function(说着很绕口,可以理解转成类似async函数)

  const converted = function (ctx, next) {
   
    return co.call(ctx, mw.call(ctx, createGenerator(next)))
  }

其实除了这个个人觉得很鸡肋的DEBUG,(感兴趣试试命令行输入 DEBUG=koa* node app.js),重点在于这个 this.middleware.push(fn);,它做的只是把中间件放进了middleware数组。

app.listen

之后我们就用到listen方法

  listen(...args) {
   
    debug('listen');
    const server = http
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值