let express = require('express');
let app = express();
这是我们常用的最基础的创建express实例的方式,然后在它的基础上在构建各自的项目,今天主要就是围绕着这个app来介绍express的源码
首先先看express目录
express/index.js =====》
express/lib/express.js =====》
createApplication()
生成app
到这边应该都显明扼要。接下来,在这个函数中,就是对app的生成操作,可以看到除了在这个文件中初始化了各种app的方法,还通过mixin操作将其他文件的app的方法给加入进来
接下去就是使用循环结构,配合原型链使用,使得app和req/res能互相利用到:
// expose the prototype that will get set on requests
app.request = Object.create(req, {
app: { configurable: true, enumerable: true, writable: true, value: app }
})
而后依旧是基础的暴露出一些基本的方法,例如router,application等
接下来是express的核心
也是前面提到的
将其他文件的方法加入进来 初始化了Application(详见点我)中的方法
此处需要注意的是路由的加载,并不是在app生成的时候加载的,而是在后期人为添加路由功能的时候动态添加
原因:路由的添加需要使用到app配置信息,为了避免路由生成的时候,app的基础配置信息还未生成,所以使用了lazyrouter(),进行到入下图的代码时再将路由生成(情况之一)
路由:
通过lib/router下路由模块生成
router/下有3个文件
index:主文件
route:路由
layer:express路由底层数据结构
所有的express中间件都存放在stack数组中,由layer生成每条数据
感兴趣的可以在自己项目里输出一下app._router.stack观察
了解了这些,那么可以刚才那张图里看到,在express路由初始化生成的时候,加入了2个默认使用的中间件
再来仔细看看路由文件
首先分析路由生成,再分析访问时路由的解析
思路与app生成大同小异,也可以看出在路由生成的时候,就生成了用来存放中间件的stack数组
需要注意的是router.handle方法就是访问时的路由解析操作
初始化生成路由————添加路由解析器(app.use/app.route/express.Router()等)———存放相应中间件到stack
再来看handle方法
首先分析下express是如何接受http请求的
可以看到整个app是被注册进createServer中的,然后进行监听
我们知道,在express/express.js中
实例化的app首先就执行了handle方法,用来处理http请求
然后去stack中找寻匹配到路由规则的中间件
不停传递next()方法按顺序执行中间件。
中间件越多,理论上来说请求处理耗时越长,
按照源码执行的中间件查找顺序可知,需要更高效率的api应当放在中间件(路由)的最前面(路由实质上也就是中间件)
引出的问题:
路由是由数组储存,并且更糟糕地采取了递归方式遍历,开销过大,未对相同路由采取过滤措施,导致会出现不必要的资源浪费