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源码剖析的主要内容,如果未能解决你的问题,请参考以下文章

express源码剖析

《Docker 源码分析》全球首发啦!

Mybatis源码剖析:传统开发方式源码剖析

Spark源码剖析:stage划分原理与源码剖析

C语言源码剖析与实现——strtok()系列函数实现

fasttext源码剖析