以Koa源码解析为例,分享学习源码的方法技巧

422 阅读4分钟

不知不觉,已经一个月没写文章了,因为刚换了工作,正好接触到了egg,以前都是只会用express起个服务,连接数据库做CRUD。没有仔细的学习一下node这门语言主流框架的演变。所以打算好好学习下框架的大致思路实现,方便以后自己造轮子。下面我就分享下我的理解,错了请轻喷,我也好再多学习点经验。

要有自己的理解

我遇到过几位前辈都跟我说过类似的话,就是学习一个框架或者封装的实现,一定要去看它的源码,直接在github上搜就好了,不要只听别人的XXX源码解析,那只是别人的见解,复杂的地方就被别人一笔带过,给你讲个思路而已。一开始我也觉得看源码很难理解,很乏味,所以内心有点抗拒,但是当我第一次学习redux源码的时候,注释多的离谱,英文也是很简单那种,遇到不理解的单词和语句就直接有道翻译划词翻译就好。所以我一般是看几遍流程,细节大致都搞不清的就去网上找资料,最起码大致的思路得捋出来

koa为何精简

核心内容就4个js文件。Koa 应用程序是一个包含一组中间件函数的对象,它是按照类似堆栈的方式组织和执行的。

1.png
图1来自源码

application

这个文件的作用是,提供了挂载中间件的方法use,并且在http.createServer的requestListener里执行了callback(compose 中间件函数列表),返回一个接收(req, res)入参的Fn. fn里根据req和res生成特定的content上下文对象,最后执行中间件compose后的函数,并且在then后返回req接口response的内容。

截屏2021-06-2306.40.41.png 图2来自node官网

截屏2021-06-2306.44.59.png 图3来自图2的最后一句的request的链接内容

来欣赏一下koa文档的经典middleware.gif,下面开始讲解

middleware.gif 图4,middleware.gif

use

截屏2021-06-2307.58.11.png 图5来自源码application

我们来看一下源码,是不是可以发现,注释很详细。定义了入参和返回,虽然没有用ts来改写但是也够用了。这里做了什么呢?接收一个Fn然后把它push到middleware数组里,最后返回this就是当前对象,所以能链式的调用use。

listen

截屏2021-06-2309.00.54.png 图六来自源码application

创建一个http服务,并且注册request事件监听。

callback

截屏2021-06-2309.04.07.png 图七来自源码application

关键库:koa-compose

通过这个就实现了,也就图四的过程。 compose方法是通过引入npm包,按住ctrl点进去发现,这个包就一个函数....

const compose = require('koa-compose');

截屏2021-06-2309.06.56.png 图八来自源码application 著名的洋葱圈模型

有没有觉得app和content这些对象很强大,怎么什么属性都有?当然是挂上去的啦。。。

截屏2021-06-2422.03.38.png 图九来自源码koa-compose 著名的洋葱圈模型

一个 ctx 即可获得所有 koa 提供的数据和方法,而 koa 会继续将这些职责进行进一步的划分,比如 request 是用来进一步封装 req 的,response 是用来进一步封装 res的,这样职责得到了分散,降低了耦合,同时共享所有资源使得整个 context 具有了高内聚的性质,内部元素互相都能够访问得到。

content

这个文件呢,主要是是事件劫持(委托)给相应的对象, 截屏2021-06-2506.56.12.png

关键库:delegates

类定义

截屏2021-06-2507.05.14.png 采用工厂模式,new一个实例。

method

截屏2021-06-2507.05.39.png

getter和setter

截屏2021-06-2507.06.13.png 实现是委托,把content的访问,委托给相应的target

截屏2021-06-2507.06.28.png

request 和 response

这个就靠大家去了解了,细节太多。当需要精读的时候,就要debug到引用的第三库,像上面的koa-compose和delegates一样,可以加console.log去打印一些日志。顺带一提的是,需要重新启动koa

最后

学习源码,可以新建个文件夹,然后npm init -y 生成默认的.json文件,然后执行npm install XXX、cnpm install XXX、 yarn XXX。(XXX为包名)然后安装好依赖后就愉快的学习了。一般TS文件的可阅读性比较强,因为都会有个抽象类告诉你这个方法是做什么的。然后去另一个文件找具体实现。碰到更完善的库还会有测试文件,测试文件里一般包含了这个库的绝大多数的使用方式,具体可以参考react hook的测试文件。
要放平心态去学习未知的东西。共勉~~