鸽了鸽了,webpack源码大垃圾,看了那么久,感觉自己越来越渣……还是换个口味,node了解一下?

  尝试从express框架源码入手,学习一下node的http模块相关的知识。

入口文件

  先从框架的主文件入手,该JS文件包含三大部分:

1、外部/工具模块引入与属性挂载

2、主函数定义

3、中间件的分离提示

  

  首先是第一块,具体的相关代码如下:

var bodyParser = require('body-parser')
var EventEmitter = require('events').EventEmitter;
var mixin = require('merge-descriptors');
var proto = require('./application');
var Route = require('./router/route');
var Router = require('./router');
var req = require('./request');
var res = require('./response'); // 内部模块 exports.application = proto;
exports.request = req;
exports.response = res; // 构造方法 exports.Route = Route;
exports.Router = Router; // 中间件 exports.json = bodyParser.json
exports.query = require('./middleware/query');
exports.static = require('serve-static');
exports.urlencoded = bodyParser.urlencoded

  昨天正正经经的刷了一遍官方文档,在API的那一块,很暴力的把express分为了5个模块:

1、express本身

2、Application

3、Request

4、Response

5、Router

  从源码来看也正是这样的,值得注意的是,express内部自带了body-parser模块,并且将该模块用来解析application/json与application/x-www-form-urlencoded形式的方法添加到了express上面。

  EventEmitter是node内置事件模块,不必多讲。剩下的就是mixin方法,可以看下源码:

var hasOwnProperty = Object.prototype.hasOwnProperty

module.exports = function merge(dest, src, redefine) {
// 错误处理
if (!dest) throw new TypeError('argument dest is required')
if (!src) throw new TypeError('argument src is required')
// 默认为true
if (redefine === undefined) redefine = true Object.getOwnPropertyNames(src).forEach(function forEachOwnPropertyName(name) {
// redefine参数的作用是在目标对象与源对象有冲突键时 是否进行覆盖定义
if (!redefine && hasOwnProperty.call(dest, name)) return // 复制所有键 包含不可枚举的
var descriptor = Object.getOwnPropertyDescriptor(src, name)
Object.defineProperty(dest, name, descriptor)
})
return dest
}

  所以说,在引入express模块后,除了直接执行获取app实例,还可以调用上面的一些方法。

  第二块就来看主函数的定义了,大部分的情况下,express的使用不外乎下面两行代码:

var express = require('express');
var app = express();

  也就是express模块本身在引入后是一个函数,而函数的源码如下:

function createApplication() {
// 返回的app实例也是一个函数
var app = function(req, res, next) {
app.handle(req, res, next);
};
// 目标对象属性的复制
mixin(app, EventEmitter.prototype, false);
mixin(app, proto, false); // 挂载req、res的属性
app.request = Object.create(req, {
app: { configurable: true, enumerable: true, writable: true, value: app }
});
app.response = Object.create(res, {
app: { configurable: true, enumerable: true, writable: true, value: app }
}); // 初始化
// 该方法来源于上面的proto
app.init();
return app;
}

  函数十分简单,首先定义了一个函数,然后将EventEmitter、proto(application)上面的属性添加到函数上,把request、response的原型设置为引入的内部模块req、res,调用init初始化方法后,返回app。

4.18后记,补充一下这里的知识点:

  这里返回函数是必要的,首先参照正常情况下创建node服务器的代码:

let http = require('http');
http.createServer((req, res) => {
// ...
}).listen(9123);

  可以看出,第二步的方法调用接受一个函数,通常我们会在这处理请求并进行响应。

  而app.listen方法(这里提前讲一下)的代码如下:

app.listen = function listen() {
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};

  可以看到,基本上就是原生的方法,对应传进去的函数变成了this,this指向什么呢?就是生成的函数,当有请求时,触发的函数就是app.handle方法。

  涉及的handle、init方法均来源于混入的proto中,这个后面再看。

  第三块就是4.x的一个变化:Express 4 不再依赖 Connect,而且从内核中移除了除 express.static 外的所有内置中间件。

  从代码来看就很直白:

// 分号确实是源码里的
// 因为上一行代码没有分号
;[
'bodyParser',
'compress',
'cookieSession',
'session',
'logger',
'cookieParser',
'favicon',
'responseTime',
'errorHandler',
'timeout',
'methodOverride',
'vhost',
'csrf',
'directory',
'limit',
'multipart',
'staticCache',
].forEach(function (name) {
// 每次尝试在express上访问这些属性将会报错
Object.defineProperty(exports, name, {
get: function () {
throw new Error('Most middleware (like ' + name + ') is no longer bundled with Express and must be installed separately. Please see https://github.com/senchalabs/connect#middleware.');
},
configurable: true
});
});

  对原有的中间件属性访问将会报错……但是问题是内部又引入了body-parser模块,看来还是不能完全脱离,偷偷用了一个。

  完结。

.1-浅析express源码之入口文件的更多相关文章

  1. Yii2 源码分析 入口文件执行流程

    Yii2 源码分析  入口文件执行流程 1. 入口文件:web/index.php,第12行.(new yii\web\Application($config)->run()) 入口文件主要做4 ...

  2. 详细解析Thinkphp5.1源码执行入口文件index.php运行过程

    详细解析Thinkphp5.1源码执行入口文件index.php运行过程 运行了public目录下的index.php文件后,tp的运行整个运行过程的解析 入口文件index.php代码如下: < ...

  3. tp3.2源码解析——入口文件

    如果有人读这篇文章并跟着做的话,希望你能使用支持函数跳转的编辑器,还要善用var_dump和exit,对着源码去调试着看.跟着入口文件读,执行到哪里你看到哪里,对于那些不能一眼看出来的配置,则要记录下 ...

  4. MyBatis 源码分析 - 映射文件解析过程

    1.简介 在上一篇文章中,我详细分析了 MyBatis 配置文件的解析过程.由于上一篇文章的篇幅比较大,加之映射文件解析过程也比较复杂的原因.所以我将映射文件解析过程的分析内容从上一篇文章中抽取出来, ...

  5. .5-浅析express源码之Router模块(1)-默认中间件

    模块application已经完结,开始讲Router路由部分. 切入口仍然在application模块中,方法就是那个随处可见的lazyrouter. 基本上除了初始化init方法,其余的app.u ...

  6. express源码分析之Router

    express作为nodejs平台下非常流行的web框架,相信大家都对其已经很熟悉了,对于express的使用这里不再多说,如有需要可以移步到www.expressjs.com自行查看express的 ...

  7. Hyperledger Fabric 1.0 从零开始(四)——Fabric源码及镜像文件处理

    2:Fabric源码及镜像文件处理 2.1下载Fabric源码 下载Fabric源码是因为要用到源码中提到的列子和工具,工具编译需要用到go语言环境,因此需要把源码目录放到$GOPATH下.通过1.3 ...

  8. 单独编译和使用webrtc音频回声消除模块(附完整源码+测试音频文件)

    单独编译和使用webrtc音频降噪模块(附完整源码+测试音频文件) 单独编译和使用webrtc音频增益模块(附完整源码+测试音频文件) 说实话很不想写这篇文章,因为这和我一贯推崇的最好全部编译并使用w ...

  9. 单独编译和使用webrtc音频降噪模块(附完整源码+测试音频文件)

    单独编译和使用webrtc音频增益模块(附完整源码+测试音频文件) 单独编译和使用webrtc音频回声消除模块(附完整源码+测试音频文件) webrtc的音频处理模块分为降噪ns,回音消除aec,回声 ...

随机推荐

  1. iOS 项目国际化(多语言支持)

    按下图步骤创建好后使用如下代码即可实现国际化:self.infoLB.text = NSLocalizedString("key", comment: "") ...

  2. unidbgrid列排序

    unidbgrid列排序 1)指定列的.sortable:=true; 2)unidbgrid.columnsort事件添加如下代码: if SameText(Column.FieldName, 'I ...

  3. Android-Recyclerview的简单使用

    由于Recyclerview是在 android.support.v7.widget.包 RecyclerView,所以需要导Recycler库: 导Recycler库: 选择项目,右键-->  ...

  4. MySQL--Percona-XtraDB-Cluster 5.6安装笔记

    安装环境: 有三台干净的CentOS 6的服务器,IP配置为:192.168.166.169,192.168.166.170,192.168.166.171,准备搭建三节点的Percona XtraD ...

  5. 【转】PowerDesigner code、name显示设置 及 同时显示办法

    原文地址:http://blog.csdn.net/fy_hanxu/article/details/52468927 菜单->Tool->Model Options->Name C ...

  6. 林纳斯·托瓦兹和Linux行为准则:揭穿7个谬论

    欢迎访问网易云社区,了解更多网易技术产品运营经验. 作者:史蒂芬·沃恩·尼古斯(Steven J.Vaughan-Nichols),从事Linux开源工作 时间:格林威治标准时间2018年9月25日— ...

  7. [leetcode.com]算法题目 - Length of Last Word

    Given a string s consists of upper/lower-case alphabets and empty space characters ' ', return the l ...

  8. Spring中使用StandardServletMultipartResolver进行文件上传

    从Spring3.1开始,Spring提供了两个MultipartResolver的实现用于处理multipart请求,分别是:CommonsMultipartResolver和StandardSer ...

  9. python音乐播放器第二版

      此代码是上一期的改版 需要用到的Python库有 .pygame 2.time 3.xmusic(我自己写的用来做音乐索引) .colorama(美观) 推荐使用pip安装 方法: pip ins ...

  10. .gitignore总结

    git进行管理时,.gitignore是必不可少的,可以指定不需要提交到仓库的资源.最好在git init之后就创建 .gitignore文件,这是个好习惯,常用的配置及说明如下: