一,开篇分析

大家好,今天这篇文章主要是对"Connect"中间件以及相关辅助中间件,做一个源码分析系列,我想上一篇文章大家也看了,

介绍了使用方式及用途,而这篇也是出于本人的兴趣,让读者对其有一个更深入的认识,如在分析阶段有什么不正确的地方,请大家多多指教,

好了!老规矩然我们进入正题。先来看一个例子,结合会用引入分析,如下:

复制代码代码如下:
 var connect = require("./lib/connect") ;
 var app = connect.createServer() ;
 app.use(connect.static(__dirname + "/public",{
    maxAge: 0 
})) ;
 app.use(function(req,res,next){
     res.end("Hello World !") ;
 })
 .listen(8888) ;

 

  二,逐行分析:

  (1),第一行,引入"connect"模块,通过connect创建一个http|https server,提供http server的所有功能。

    "connect"中间件允许你用多种方式创建"server",   

复制代码代码如下:
var server = connect.createServer(
     connect.logger()
    , connect.static(__dirname + '/public')
) ; // 1
var app = connect() ;
app.use(function (req,res) {
    res.end("Hello,大雄君 !\n")  ;
}).listen(8888)  ; // 2

  那么它是如何做的那,看源码:

复制代码代码如下:
exports = module.exports = createServer ;
exports.createServer = createServer ;

  将“createServer”挂载到全局的“exports”上,然后再扩展一个“createServer”属性再次挂载,目的是为了兼容原生的书写形式,

达到了不同方式创建的目的。这也是大家在平时开发中可以借鉴的思想。

  (2),再来看第二行"connect.createServer",做了什么那,看如下源码:

复制代码代码如下:
 var HTTPServer = require('./http').Server , 
 HTTPSServer = require('./https').Server ;
 function createServer() {
   if ('object' == typeof arguments[0]) {
     return new HTTPSServer(arguments[0], Array.prototype.slice.call(arguments, 1));
   } else {
     return new HTTPServer(Array.prototype.slice.call(arguments));
   }
 };

  "HTTPSServer"和"HTTPServer"基本一致,只是"HTTPSServer"封装的https的方法。在"createServer"的时候,同样可以传递进去一系列的中间件,和随后引入的效果是一样的,不过却只能绑定到根目录上。

  (3),继续看第三行"app.use()",做了什么那,看如下源码:  

复制代码代码如下:
 var Server = exports.Server = function HTTPServer(middleware) {
   this.stack = [];
   middleware.forEach(function(fn){
     this.use(fn);
   }, this);
   http.Server.call(this, this.handle);
 };
 /**
  * Inherit from `http.Server.prototype`.
  */
 Server.prototype.__proto__ = http.Server.prototype;

  “connect"是原型继承于"http server"的,它会用use到的中间件替换掉server的requestListener。

  通过"connect.use(route, handle)"来对每一个路由添加中间件,这些中间件"handle"会与"route"绑定保存在一个"stack"里面,每次有"request"请求的时候,

  遍历这个堆,找到对应"route"的"handle",执行"handle",如果"handle"最后调用了"next()",就会继续寻找并执行下一个匹配的"handle"。

  通过封装"handle",可以很容易的在"connect"基础上添加更多的"middleware"。

 (4),最后看看"listen(8888)",它做些什么工作那?

    很简单,通过继承底层的Server对象,赋予了"listen"的功能,监听特定端口。

    Server.prototype.__proto__ = http.Server.prototype

 以下是”connect.js“的全部源码,为了节省篇幅,注释已全部删掉,如下图:

  补充一下:

复制代码代码如下:
 fs.readdirSync(__dirname + '/middleware').forEach(function(filename){
   if (/\.js$/.test(filename)) {
     var name = filename.substr(0, filename.lastIndexOf('.'));
     exports.middleware.__defineGetter__(name, function(){
       return require('./middleware/' + name);
     });
   }
 });

  将"middleware"对象"exports",然后循环定义给"middleware"对象一种方法,这种方法是直接加载 "middleware" 文件夹中的.js文件模块。

利用:"exports.utils.merge(exports, exports.middleware)" 这句话将middleware中的方法直接exports了。

三,总结一下:

   (1),理解源码的设计意图,有助于在应用上得到最大化的收获。

   (2),看源码时,理解流程再去扣语法细节。

   (3),借鉴源码中的巧妙实现思想,但不要过渡设计,为了设计而设计。

   (4),明天继续分析相关中间件,不断更新中 。。。 。。。

NodeJS学习笔记之Connect中间件模块(二)的更多相关文章

  1. NodeJS学习笔记之Connect中间件模块(一)

    NodeJS学习笔记之Connect中间件模块(一) http://www.jb51.net/article/60430.htm NodeJS学习笔记之Connect中间件模块(二) http://w ...

  2. NodeJS学习笔记之Connect中间件应用实例

    一,开篇分析 大家好哦,大熊君又来了,昨天因为有点个人的事没有写博客,今天又出来了一篇,这篇主要是写一个记事本的小应用,前面的文章, 我也介绍过“Connect”中间件的使用以及“Mongodb”的用 ...

  3. Nodejs学习笔记(三)--- 模块

    目录 简介及资料 自定义模块 创建一个自定义模块 调用自定义模块 exports和module.exports 区别 exports和module.exports 覆盖 其它... 简介及资料 通过N ...

  4. Nodejs学习笔记(三)—模块

    简介及资料 通过Node.js的官方API可以看到Node.js本身提供了很多核心模块 http://nodejs.org/api/ ,这些核心模块被编译成二进制文件,可以require('模块名') ...

  5. nodejs学习笔记之包、模块实现

        简单了解了node的安装和一些基本的常识之后,今天学习了node中很重要的包和模块的一些知识点.       首先学习一下包的规范,它由包结构和包描述两部分组成.包结构用于组织包的各种文件,包 ...

  6. NodeJS学习笔记 (27)实用工具模块-util(ok)

    debuglog(section) 很有用的调试方法.可以通过 util.debuglog(name) 来创建一个调试fn,这个fn的特点是,只有在运行程序时候,声明环境变量NODE_DEBUG=na ...

  7. NodeJS学习笔记 进阶 (12)Nodejs进阶:crypto模块之理论篇

    个人总结:读完这篇文章需要30分钟,这篇文章讲解了使用Node处理加密算法的基础. 摘选自网络 Nodejs进阶:crypto模块之理论篇 一. 文章概述 互联网时代,网络上的数据量每天都在以惊人的速 ...

  8. Nodejs学习笔记(二)——Eclipse中运行调试Nodejs

    前篇<Nodejs学习笔记(一)——初识Nodejs>主要介绍了在搭建node环境过程中遇到的小问题以及搭建Eclipse开发Node环境的前提步骤.本篇主要介绍如何在Eclipse中运行 ...

  9. Nodejs学习笔记(六)--- Node.js + Express 构建网站预备知识

    目录 前言 新建express项目并自定义路由规则 如何提取页面中的公共部分? 如何提交表单并接收参数? GET 方式 POST 方式 如何字符串加密? 如何使用session? 如何使用cookie ...

随机推荐

  1. [NOIP模拟13]题解

    A.矩阵游戏 其实挺水的? 考场上根本没有管出题人的疯狂暗示(诶这出题人有毛病吧这么简单的东西写一大堆柿子),而且推公式能力近乎没有,所以死掉了. 很显然乘法有交换率结合率所以操作顺序对最终结果没什么 ...

  2. [NOIP模拟测试7]visit 题解(组合数学+CRT+Lucas定理)

    Orz 因为有T的限制,所以不难搞出来一个$O(T^3)$的暴力dp 但我没试 据说有30分? 正解的话显然是组合数学啦 首先$n,m$可能为负,但这并没有影响, 我们可以都把它搞成正的 即都看作向右 ...

  3. Guava EventBus集成spring

    EventBus 不是通用的消息系统,也不是用来做进程间的通信的,而是在进程内,用于解耦两段直接调用的业务逻辑: 1.代码结构 event:eventbus中流转的事件(消息),包结构按照业务模块在细 ...

  4. 9. Python函数

    函数 函数能提高应用的模块性,和代码的重复利用率.定义一个函数比较简单,但是需要遵循以下几点规则: 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 (). 任何传入参数和自变量必须放在圆 ...

  5. 7. Python运算符之逻辑、成员、身份运算符及优先级

    运算符 逻辑表达式 描述 and x and y 布尔"与" - 如果 x 为 False,x and y 返回 False,否则它返回 y 的计算值. or x or y 布尔& ...

  6. scala 集合类型

    Iterable 是序列(Seq), 集(Set) 映射(Map)的特质 序列式有序的集合如数组和列表 集合可以通过== 方法确定对每个对象最多包含一个 映射包含了键值映射关系的集合 列表缓存: 使用 ...

  7. pcA降维 SVD

    前言: PCA的实现一般有两种,一种是用特征值分解去实现的,一种是用奇异值分解去实现的.在上篇文章中便是基于特征值分解的一种解释.特征值和奇异值在大部分人的印象中,往往是停留在纯粹的数学计算中.而且线 ...

  8. 31-Ubuntu-用户权限-02-ls输出信息介绍

    ls -l 查看文件夹下文件或目录的详细信息 1 2 3 4 5 6 7 8 9 10 d/- rwx rwx r-x 2 summmer summmer 12288 2月 25 13:34 Ente ...

  9. ForEach控制器

    ForEach一般是和用户定义的变量结合使用的 前面前缀一般是和用户定义的变量前缀一致 输出的变量是要使用的变量 这样能保证每次使用的变量不一样 add"_"before numb ...

  10. Mac OS X终端的常用操作命令(UNIX指令)

    用了十多年windows,终于换了个高配Mac,俗话说 无论前端还是后端最终还是走向了linux,无论是换了多少台PC最终都会走向Mac.不学习命令行用什么Mac? 干就完了~ pwd 显示现在的文件 ...