express源码剖析
Posted anthonyliu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了express源码剖析相关的知识,希望对你有一定的参考价值。
express/appliction.js
application.js对外的方法可以分成四类:
- 设置/初始化成员变量,主要是对成员变量settings进行设置,这样的方法有:enabled、enabled、disabled、 disable和set方法。
- 设置路由和对每个路由设置中间件:这样的方法有:use.router,all,param和methods方法。
- 设置模板引擎的方法:engine和render。
- 启动node服务器对res和req操作的方法:listen和handler。
1.解析app.engine方法
express的api中有app.engine方法,例如:
app.engine("handlebars",handlebars.engine);
看下这个函数的的核心代码就是:
// get file extension,ext为文件扩展名 var extension = ext[0] !== \'.\' ? \'.\' + ext : ext; // store engine this.engines[extension] = fn;
1.2 解析app.use方法
//use的使用
var express = require(\'express\'); var app = express(); function handlerWrap(){ console.log("1"); } app.use("/", handlerWrap); //路径/会调用hanlerWrap方法
进入app.user源码:
this.lazyrouter(); app.lazyrouter = function lazyrouter() { //给a公有变量_router赋值,它是对象Router的实例。 if (!this._router) { //实例化Router this._router = new Router({ caseSensitive: this.enabled(\'case sensitive routing\'), //false strict: this.enabled(\'strict routing\') //false }); //router.use(path,fn); 为path建立layer,有多少个fn,就建立多少个Layer,然后把这个layer压入router.stack数组中。 this._router.use(query(this.get(\'query parser fn\'))); //this.get(\'query parser fn\')为一个函数: this._router.use(middleware.init(this)); } };
看看router的构造函数,它在express/lib/router/index.js文件中,express功能核心都在这个文件,它的定义和app的定义很类似。
if (!fn || !fn.handle || !fn.set) { //handlerWrap函数为handler、 set成员!,如果fn函数没有handle,或者set函数,调用router.use(path,fn)。也就是说那不是express的实例,大部分插件都会直接执行。 return router.use(path, fn); //rounter.use直接把该函数构造成一个Layer成员,实际上是给router.stack添加一个layer成员。 } debug(\'.use app under %s\', path); fn.mountpath = path; //如果是express的对象,那么给express这个对象成员mountpath赋值为path(可能含有正则); fn.parent = this; //fn变成子express对象,当前的express为父。 // restore .app property on req and res //执行use,封装了fn, router.use(path, function mounted_app(req, res, next) { var orig = req.app; //这里看的不太懂。 fn.handle(req, res, function (err) { req.__proto__ = orig.request; res.__proto__ = orig.response; next(err); }); }); // mounted an app console.log("fn="+JSON.stringify(fn)); fn.emit(\'mount\', this); // 进入router/index.js中,执行proto.use()方法。 // 实际上是给router.stack添加一个layer成员, var layer = new Layer(path, { sensitive: this.caseSensitive, strict: false, end: false }, fn); layer.route = undefined; //给layer.route赋值undefined this.stack.push(layer);
同理:this._router.use(middleware.init(this))的作用是把该函数,构造成一个Layer成员,然后是给router.stack添加一个layer成员。
//middleware.init(this)返回的是下列函数:
return function expressInit(req, res, next){ if (app.enabled(\'x-powered-by\')) res.setHeader(\'X-Powered-By\', \'Express\'); req.res = res; res.req = req; req.next = next; req.__proto__ = app.request; res.__proto__ = app.response; res.locals = res.locals || Object.create(null); next(); };
在express初始的时候,router的stack数组中有两个回调函数了。所有调用app.user(fn),都是给rounter的stack数组中添加回调函数,
express中的路由机制,可以参考链接:http://cnodejs.org/topic/545720506537f4d52c414d87,里面说的非常具体!
以上是关于express源码剖析的主要内容,如果未能解决你的问题,请参考以下文章