超轻量级web框架koa源码阅读

koa是一个很是轻量的web框架,里面除了ctx和middleware以外什么都没有,甚至连最基本的router功能都须要经过安装其余中间件来实现。不过虽然简单,可是它却很是强大,仅仅依靠中间件机制就能够构建完整的web服务。而koa的源码一样很简洁,基础代码只有不到2000行,很是适合阅读学习。node

koa的源码直接从github获取,本文采用目前最新的2.5.1版本。git

代码结构

第一眼看到koa的源码时候我真的懵了,反复确认没有看错以后才确信,koa源码只有四个文件--application.js,context.js,request.js,response.js,位于项目的lib文件夹下。并且一看文件名基本上就能猜到每一个文件是作什么的了,接下来就是打开查看里面的内容。github

koa基本启动流程

首先看package.json里面的main,能够知道application.js是入口文件,里面是一个继承自event模块下的Emitter类的Application类,咱们使用koa时候建立的app实例就是在这里定义的。web

分析一个类天然要先看它的构造函数,里面重点的就是定义了一个数组middleware,还有三个属性context,request,response分别为三个对象,而这三个对象就是在对应的其余三个文件中定义的。在此咱们先不看另外的文件,想一想咱们使用koa的时候,建立app实例以后,接下来就是use各类中间件了,因此直接看use方法。json

use接收一个中间件函数做为参数,首先作类型校验,若是传入的是generator,在koa2中会先经过convert进行转换(此处是为了兼容koa1,后续版本将移除),最后其实只作了一件事,就是把这个函数push到middleware数组中去。use方法最后会返回this,也就是koa实例自己,这就意味着咱们能够实现链式调用。数组

设置好中间件,咱们开启koa服务的最后一步就是调用listen方法设置监听端口,接下来就看一下listen方法的实现。咱们会发现listen更简单,只有两行,其实什么额外的事情也没作,只是调用了node原生的http模块下面的createServer方法建立服务,listen方法设置监听,仅此而已。咱们都知道http的createServer须要传入一个函数,这个函数在koa里面是经过调用callback方法返回的,接下来看callback的实现。promise

callback里面首先使用compose把全部的中间件变成一个函数(compose的实现一样后续会详细分析),这里会首先调用Emitter中的listenerCount方法判断是否有error事件的监听器,若是没有会为error事件注册默认的事件监听方法onerror,以后就是定义咱们要的那个传入createServer的函数了。这个函数接收req和res两个参数,以后,koa会对其作一个处理:经过调用createContext方法把req和res封装成咱们熟悉的ctx对象(createContext具体作了哪些工做接下来会说),而后把ctx和以前处理好的中间件函数fnMiddleware传入handleRequest方法中。app

handleRequest中首先先取出res,先把状态置为404,而后对执行中间件后的成功和失败状态注册方法,失败调用ctx.onerror捕获异常,成功调用respond方法处理结果。这里仍是用了onFinished模块,onFinished能确保一个流在关闭、完成和报错时都会执行相应的回调函数,这里把咱们的异常处理函数传入用以处理错误信息。而respond方法,里面作的,就是读取ctx信息,把数据写入res中并响应请求。至此,整个流程就完成了。框架

ctx的建立

createContext里面的代码其实特别简单,就是建立了三个对象context,request,response,而后把使用ctx时候的各类东西都挂到context对象上,这样咱们就能够在ctx上面获取到req,res等等各类信息了。建立context,request,response对象时候用到了当前app类里面的三个对象,它们是经过从外部三个文件中引入的对象来建立的,因此接下来就看一下这三个文件中都有什么。koa

这三个文件导出的都是对象,在context中,只作了一些基础方法的定义,剩下的一切属性方法所有都使用delegate代理到request和response属性的访问了。而前面咱们已经知道,context上面的request和response就是经过另外的两个文件中的对象建立获得的。而这两个文件的内容就更加简洁了,都是咱们平时使用时候访问的属性和方法,经过getter和setter的方式来控制上面的req和res从而实现对实际请求和响应操做的封装。因而整个koa核心的四个文件就完全完成了。

compose实现原理与中间件机制

首先作一些合法性校验,重点在于最后的返回结果是一个函数,这个函数就是咱们上面的fnMiddleware,它一样也有context和next两个参数,在其内部采用index变量记录当前处理到哪一个中间件,而后从第一个开始调用dispatch方法。首先会判断当前传入参数与index的关系,若是在一个中间件内屡次调用next,会出现参数小于index的状况,此时就会报错。以后把当前中间件从数组中取出来,每次执行时会把ctx和next传入,next中调用dispatch,参数为下一个位置,这样就会按顺序把中间件添加进来,最后当i等于中间件数组长度时候,也就是没有其余中间件了,那么执行一开始传入的next参数,若是fn不存在,返回空的promise。当中心执行完,也就是前一个中间件的next执行完,天然会触发await向下执行,以后执行权会反向顺序返回,最终组合的结果就是先从外向里,再从里向外,就是咱们熟知的洋葱圈模型。

错误处理机制

koa的错误处理机制也颇有特色,咱们只要监听koa实例的error事件,就能够统一处理全部的错误。咱们在前面提到过,调用fnMiddleware失败后会被统一的onerror方法捕获,这个方法是对应到ctx上的onerror方法,咱们来看一下里面的实现,里面很是重要的一行就是this.app.emit('error', err, this);,因为咱们的koa是继承自event,因此能够派发出一个error事件,咱们只要处理该事件便可。而前面在中间件处理中,若是发生错误就会reject,天然能够被catch捕获到。

以上,就是koa基本核心模块的流程,原理很简单,可是配合各类中间件,koa彻底能够实现一个功能完整web server。

本文原创,愿意分享但转载请提早告知,更多文章查看个人主页,感谢阅读,如错误欢迎指正。

相关文章
相关标签/搜索