先上传tj大神的照片,表示膜拜
刚知道,他是学设计的,刚知道他长得也这么设计,也刚听说,要想成为他一样的大神,要读源码。于是有了这篇文章。
express 框架
- application, request, response, router 四大块
- 核心的思想是中间件,基础是node的http模块
- 中间件的基础是 layer, 核心是router
application
express 返回的 createApplication方法,在当在应用层执行const app = express()的时候,返回的还是一个函数 function(req, res, next){ ... app.handle ...},application 的作用就是在app上挂载,自己封装的request,response,mixin继承proto, EventEmitter.prototype对象方法。
function createApplication() {
var app = function(req, res, next) {
app.handle(req, res, next);
};
mixin(app, EventEmitter.prototype, false);
mixin(app, proto, false);
// expose the prototype that will get set on requests
app.request = Object.create(req, {
app: { configurable: true, enumerable: true, writable: true, value: app }
})
// expose the prototype that will get set on responses
app.response = Object.create(res, {
app: { configurable: true, enumerable: true, writable: true, value: app }
})
app.init();
return app;
}
中间件
- application 的主要扩展在 proto,分析的时候主要抓住 app = handle(req, res, next)。由app.handle 到 router.handle,主要逻辑就在此。
- node 模块http创建web服务类似 http.createServer(app).listen(80); 框架的重点是封装app。app就是中间件的有序执行集合。
- 什么中间件的重点是 app.use 和 app[method]。
var express = require('./index');
var app = express();
// 声明中间件
app.use(function cc(req,res,next){
console.log("111");
next();
})
app.get('/users', function(req, res, next) {
console.log(11111)
next();
}, function(req, res, next) {
console.log(22222)
next();
}, function(req, res, next) {
console.log(33333)
next();
}, function(req, res, next) {
console.log(44444)
res.send('hello world')
})
var server = app.listen(8081, function() {
var host = server.address().address
var port = server.address().port
console.log("应用实例,访问地址为 http://%s:%s", host, port)
})
打印中间件:
注意:前两个中间件是框架自带,第三个是use声明的中间件,第四个是app[method]声明的。
- 有序执行是声明的顺序 和 next 方法
next 有两个 router/index.js 和 router/route.js 文件中各有一个next
*** 第一个next是上图中四个红色箭头指向的中间件依次执行的保证。
*** 第二个next是第四个箭头中route.stack各个layer顺序执行的保证。
app中的 res, req, next 就是这么一个layer 传到下一个layer。碰到route不等于undefined时候,在进入下一层 layer,直到最后一个中间件,调用res.send 终结返回,完成一个http请求。
router.handle里面 next() 函数是处理各种中间件的。while 循环遍历 stack(初始化所有中间件的数组)。遍历出所有符合当前路由中间件(layer),
next 一个一个处理,然后返回。
response / request
相对比较简单,关键是看如何跟框架结合。
- request.js 中 var req = Object.create(http.IncomingMessage.prototype); req 是基于node http模块当原型链重新声明 req。又在req自身属性上挂在一些自定义的常用到的方法。
- 同理 response.js 中 var res = Object.create(http.ServerResponse.prototype); res 也是基于node http重新声明的。挂在自己的常用函数。
application中。自己封装的res, rep都是直接挂在到app静态属性上的。- 1: 是为了暴露出去,用户可以自行扩展。
-
2: 是为了柯里化,传入到中间件中。
在每个声明中间件 无论使用use 还是什么app[method] 都需要先执行 lazyrouter
第一个use 默认的中间件是为了处理请求参数匹配路径
第二个use 是为了初始化res和req
注意:其实并没有执行,只是先把app 传过去,app上挂在了,res, rep 返回了一个中间件,当用户请求的时候,先去执行这个中间件。
感悟
分析别人源码,是习惯,先掌握主要脉络反推用户的框架思想,提升格局。在逐行分析,理解框架写法的优雅。先抓大放小,再锱铢必较。