使用express时,代码会这样写:

var express = require('express');

创建一个express的应用,代码:

var app = express();

那么express()是什么?它执行createApplication()

//express.js
exports = module.exports =createApplication;
/**
* Create an express application.
*
* @return {Function}
* @api public
*/ function createApplication() {
var app = function(req, res, next) {
app.handle(req, res, next);
}; mixin(app, EventEmitter.prototype, false);
mixin(app, proto, false); app.request = { __proto__: req, app: app };
app.response = { __proto__: res, app: app };
app.init();
return app;
//执行的结果就是app是一个实例,它有私有成员对象:request和 response,同时继承Event模块中的EventEmitter的原型。
}

在express.js中,要区分下面两个包:

var Route = require('./router/route');
var Router = require('./router');
//对外都暴露Route和Router,他们两者有些不同,
//Router是Route的超集,两者的联系只在Router.route用到。调用Router.route会得到一个route,不过给Router.stack添加了一个Layer,
//该Layer通过Router的参数和route.dispatch和用户的path来定义的。
//route只有三个成员,stack数组(储存Layer对象),path(路由的路径)和method对象。
//其中stack数组与Router一样,同时两个对象的原型都有methods的和all的方法
exports.Route = Route;
exports.Router = Router;

express也继承了application.js中的方法。执行app.init();

app.init = function init() {
//给app类/对象赋值三个公用成员, 在初始的过程中,有一个成员变量很关键,就是router
this.cache = {};
this.engines = {};
this.settings = {};
// 初始化配置,在研究defaultConfiguration之前,抽象下app.set函数,它就是给setting赋值的函数,同时针对key = "etag" 和 query parser以及"trust proxy"进行特殊的的设置。
this.defaultConfiguration();
};

app还挂有很多方法,这些可以在express的api中的application的方法找到!其中最重要的方法是app.use,它用来构造路由所执行的函数的一个数据结构_router,express在执行过程中,会遍历这个结构。

1.1app.use方法

//use的使用
var express = require('express');
var app = express();
function handlerWrap(){
console.log("1");
}
app.use("/", handlerWrap); //路径/会调用hanlerWrap方法

 app.use源码

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数组中。初始定义了两个Layer
this._router.use(query(this.get('query parser fn')));
//this.get('query parser fn')为一个函数:
this._router.use(middleware.init(this));
}
};
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);

 

express源码剖析2的更多相关文章

  1. express源码剖析1

    在通读源码之前,先把一些比较难理解的代码吃透: 1.EventEmitter.prototype mixin(app, EventEmitter.prototype, false); app为一个函数 ...

  2. express源码剖析--Router模块

    1.加载模块执行代码: methods.forEach(function(method){ //method是http协议的各种请求方法,如:get,put,headee,post Route.pro ...

  3. Node 进阶:express 默认日志组件 morgan 从入门使用到源码剖析

    本文摘录自个人总结<Nodejs学习笔记>,更多章节及更新,请访问 github主页地址.欢迎加群交流,群号 197339705. 章节概览 morgan是express默认的日志中间件, ...

  4. STL源码剖析——hashtable

    二叉搜索树具有对数时间的搜索复杂度,但是这样的复杂度是再输入数据有足够的随机性的假设上哈希表在插入删除搜索操作上也具有常数时间的表现,而且这种表现是以统计为基础,不需要依赖输入元素的随机性 hasht ...

  5. jQuery之Deferred源码剖析

    一.前言 大约在夏季,我们谈过ES6的Promise(详见here),其实在ES6前jQuery早就有了Promise,也就是我们所知道的Deferred对象,宗旨当然也和ES6的Promise一样, ...

  6. Nodejs事件引擎libuv源码剖析之:高效线程池(threadpool)的实现

    声明:本文为原创博文,转载请注明出处. Nodejs编程是全异步的,这就意味着我们不必每次都阻塞等待该次操作的结果,而事件完成(就绪)时会主动回调通知我们.在网络编程中,一般都是基于Reactor线程 ...

  7. Apache Spark源码剖析

    Apache Spark源码剖析(全面系统介绍Spark源码,提供分析源码的实用技巧和合理的阅读顺序,充分了解Spark的设计思想和运行机理) 许鹏 著   ISBN 978-7-121-25420- ...

  8. 基于mybatis-generator-core 1.3.5项目的修订版以及源码剖析

    项目简单说明 mybatis-generator,是根据数据库表.字段反向生成实体类等代码文件.我在国庆时候,没事剖析了mybatis-generator-core源码,写了相当详细的中文注释,可以去 ...

  9. STL"源码"剖析-重点知识总结

    STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略多 :) 1.STL概述 STL提供六大组件,彼此可以组合 ...

随机推荐

  1. live555源码研究(一)------live555MediaServer的启动过程和基本类图

    live555MediaServer.cpp就是live555服务器启动的过程. 一.启动过程 1,构造运行环境,运行环境包括了TaskScheduler 2,构造鉴权数据,也就是登陆的用户名和密码等 ...

  2. nginux做反向代理配置文件

    做反向代理的配置文件最好单独创建一个文件,然后在主配置文件中使用 include nginx-test.config;  这样的方式来导入. 配置代码如下: ## Basic reverse prox ...

  3. 你只是看起来很努力(只是做了一遍真题,草草的对了一遍答案,然后冲出自习室继续她学生会的事情了,骗自己更容易)good——想起了自己在六大时候的无奈

    (转)你只是看起来很努力一次上课,一个女孩子垂头丧气的跟我说,老师,我考了四次四级,还没过,究竟是为什么. 我说,你真题做了吗?单词背了吗?她拿出已经翻破了的真题,跟我说,你讲的所有的题目我连答案都记 ...

  4. UVA548——Tree(中后序建树+DFS)

    Tree You are to determine the value of the leaf node in a given binary tree that is the terminal nod ...

  5. open/write/read

    C语言中open函数 作用:打开和创建文件. 简述: 1 2 3 4 #include <fcntl.h> int open(const char *pathname, int flags ...

  6. Git教程(6)常用技巧之远程分支简单示例

    基础 1,"master" 与"origin" “master” 是当你运行 git init 时默认的起始分支名字,原因仅仅是它的广泛使用,“origin” ...

  7. TreeList 实现多表头

    1. 先上图: 2. 再上代码: 原码

  8. [转]ASP.NET MVC Jquery Validate 表单验证的多种方式介绍

    在我们日常开发过程中,前端的表单验证很重要,如果这块处理不当,会出现很多bug .但是如果处理的好,不仅bug会很少,用户体验也会得到很大的提升.在开发过程中我们可以不借助 JS 库,自己去手写 JS ...

  9. Live555研究之二Sleep实现

    Live555通过一个while循环来不断读取socket,判断是否有连接进来,但是Live555并没有使用Sleep函数来让线程休眠多少毫秒来降低CPU占用率.Live555是通过select函数来 ...

  10. 【JMeter】Jmeter引入第三方jar包

    Jmeter做remoteService,里面用到一个实体:clickEntity,是在一个第三方jar包定义的:com.bj58.opt.ad_logparser-0.0.18-SNAPSHOT.j ...