.1-浅析express源码之入口文件
鸽了鸽了,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源码之入口文件的更多相关文章
- Yii2 源码分析 入口文件执行流程
Yii2 源码分析 入口文件执行流程 1. 入口文件:web/index.php,第12行.(new yii\web\Application($config)->run()) 入口文件主要做4 ...
- 详细解析Thinkphp5.1源码执行入口文件index.php运行过程
详细解析Thinkphp5.1源码执行入口文件index.php运行过程 运行了public目录下的index.php文件后,tp的运行整个运行过程的解析 入口文件index.php代码如下: < ...
- tp3.2源码解析——入口文件
如果有人读这篇文章并跟着做的话,希望你能使用支持函数跳转的编辑器,还要善用var_dump和exit,对着源码去调试着看.跟着入口文件读,执行到哪里你看到哪里,对于那些不能一眼看出来的配置,则要记录下 ...
- MyBatis 源码分析 - 映射文件解析过程
1.简介 在上一篇文章中,我详细分析了 MyBatis 配置文件的解析过程.由于上一篇文章的篇幅比较大,加之映射文件解析过程也比较复杂的原因.所以我将映射文件解析过程的分析内容从上一篇文章中抽取出来, ...
- .5-浅析express源码之Router模块(1)-默认中间件
模块application已经完结,开始讲Router路由部分. 切入口仍然在application模块中,方法就是那个随处可见的lazyrouter. 基本上除了初始化init方法,其余的app.u ...
- express源码分析之Router
express作为nodejs平台下非常流行的web框架,相信大家都对其已经很熟悉了,对于express的使用这里不再多说,如有需要可以移步到www.expressjs.com自行查看express的 ...
- Hyperledger Fabric 1.0 从零开始(四)——Fabric源码及镜像文件处理
2:Fabric源码及镜像文件处理 2.1下载Fabric源码 下载Fabric源码是因为要用到源码中提到的列子和工具,工具编译需要用到go语言环境,因此需要把源码目录放到$GOPATH下.通过1.3 ...
- 单独编译和使用webrtc音频回声消除模块(附完整源码+测试音频文件)
单独编译和使用webrtc音频降噪模块(附完整源码+测试音频文件) 单独编译和使用webrtc音频增益模块(附完整源码+测试音频文件) 说实话很不想写这篇文章,因为这和我一贯推崇的最好全部编译并使用w ...
- 单独编译和使用webrtc音频降噪模块(附完整源码+测试音频文件)
单独编译和使用webrtc音频增益模块(附完整源码+测试音频文件) 单独编译和使用webrtc音频回声消除模块(附完整源码+测试音频文件) webrtc的音频处理模块分为降噪ns,回音消除aec,回声 ...
随机推荐
- centos rpm包下载地址
这个是6.5的下载地址,其他版本可以退回目录找相应的版本 http://vault.centos.org/6.5/updates/x86_64/Packages/
- maven 添加jdbc6
1 把jdbc6 拷贝到C:\Users\{用户}\ 2 mvn install:install-file -DgroupId=com.oracle -DartifactId=ojdbc6 -Dver ...
- 利用Delphi编程控制摄像头(图)
你的电脑有没有摄像头?看到别人用QQ玩视屏你会不会去想怎么实现的?这里介绍使用DELPHI使用MS的 AVICAP32.DLL就可轻松的实现对摄像头编程,如果再加上你的网络编程水平,实现一个视屏聊天就 ...
- Spring下配置几种常用连接池
1.连接池概述 数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出.对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标.数据库连接池正是 ...
- [Erlang02] 那些经历过的Erlang小坑1-10
1. 保护式(guard)中如果出错,不会报错,只会返回false! case 1=:1 of true when not erlang:length(t) =:= 1 orelse true -&g ...
- WPF实战案例-打印
在前段时间做了一下打印,因为需要支持的格式比较多,所以wpf能打印的有限分享一下几种格式的打印(.xls .xlsx .doc .docx .png .jpg .bmp .pdf) 首先为了保证exc ...
- MVC 5使用ViewData(对象)显示数据
控制器协调处理好数据之后,是交由视图来显示数据.在控制器与视图交互有一个是ViewData.这次练习,Insus.NET就以它来做实例. 前些时间,Insus.NET实现的练习中,也有从控制器传数据给 ...
- FFmpeg简易播放器的实现-视频播放
本文为作者原创:https://www.cnblogs.com/leisure_chn/p/10047035.html,转载请注明出处 基于FFmpeg和SDL实现的简易视频播放器,主要分为读取视频文 ...
- Git安装学习记录
1.下载: https://gitforwindows.org/ 2.安装:https://blog.csdn.net/chengyuqiang/article/details/54178683 3. ...
- Java知识锦囊
最近突然想回顾一下之前的文章,回顾复习一下,正好把觉得还不错的文章收录到这里,方便查阅 Java 2018-04-02 Java计数器之CountDownLatch.CyclicBarrier.Sem ...