.1-浅析express源码之入口文件

匿名 (未验证) 提交于 2019-12-02 21:53:52

  鸽了鸽了,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。

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

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模块,看来还是不能完全脱离,偷偷用了一个。

  完结。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!