likes
comments
collection
share

express源码分析1:express实例的构造函数

作者站长头像
站长
· 阅读数 13

这篇文章是express源码阅读系列文章的第一篇,这个系列的文章主要目的是想从一个Node.js的初学者的视角,结合express的API文档去分析解读express这个热门库的实现原理。

express的入口

从使用者的角度来看,express的入口应该是:

const express = require('express');

通过express仓库的package.json以及index.js可以看出,express整体的入口位于./lib/express。如下图

express源码分析1:express实例的构造函数

./lib/express主要包含以下几个部分:

  1. express实例的构造函数:createApplication
  2. express提供的实例对象:application、request、response
  3. express提供的路由功能: Router,Route
  4. express默认支持的middlewares: express.json()、express.query()等

这几个部分基本上可以和express的API文档对应起来

express源码分析1:express实例的构造函数

2、3、4部分主要就是简单的赋值导出,不做过多的分析

express实例的构造函数

通常在使用express的时候会出现以下代码:

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

而前面提到的createApplication就是对应我们调用的express().

function createApplication() {
  var app = function(req, res, next) {
    app.handle(req, res, next);
  };

  mixin(app, EventEmitter.prototype, false);
  mixin(app, proto, false);

  // expose the prototype that will get set on requests
  app.request = Object.create(req, {
    app: { configurable: true, enumerable: true, writable: true, value: app }
  })

  // expose the prototype that will get set on responses
  app.response = Object.create(res, {
    app: { configurable: true, enumerable: true, writable: true, value: app }
  })

  app.init();
  return app;
}

express实例的类型

createApplication的返回值是一个function,而且是在express使用中很常见的listener

var app = function(req, res, next) {
    app.handle(req, res, next);
};

也就是说,创建的express实例本质上是一个listener,至于怎么使用,我们需要额外延伸一下Node.js中http模块提供的createServer方法。下面是一个简单的示例

const http = require('node:http');

// Create a local server to receive data from
const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    data: 'Hello World!',
  }));
});

server.listen(8000);

结合上面的代码,可以发现express实例其实和Node API创建一个HttpServer所需要的listener参数很相似,为了不延伸太多额外的知识,我们先可以简单粗暴的理解为:express实例其实就是一个封装过的HttpServer对应的listener,这个listener会在创建HttpServer的时候被使用。

express实例上的方法挂载

createApplication中我们接下来会看到两个mixin相关的逻辑mixin使用的是merge-descriptors这个库,所以这两行本质上都是在拓展express实例上的属性和方法。

mixin(app, EventEmitter.prototype, false);

通过合并EventEmitter的原型,让express实例上拥有了ononce等这些事件监听方法。

mixin(app, proto, false);

这一行则是给express实例上拓展更多的自定义方法,proto内容比较多,这边不做过多的延伸。

express实例上的request、response对象

在创建express实例的时候,会给实例增加requestresponse这两个属性,主要包含一下关键点

  1. 它们分别是以 express自己提供的requestresponse为原型 创建
  2. express自己提供的requestresponse为原型 分别是以Node。js的http模块中的http.IncomingMessage.prototypehttp.ServerResponse.prototype创建,并在上面拓展了一些自定义方法。
  3. 实例上的requestresponse属性都额外增加了实例的引用,方便在处理请求和响应的时候,可以同时访问和修改express实例

app.init()

这部分延伸的知识比较多,后面会放在express中application对象中去分析。

总结

这篇文章的重点主要分析了express实例的构造函数,函数本身内容比较少不过十多行代码,但是带出了一个重点知识:express实例是一个封装过的HttpServer对应的listener ,这个知识点将会在后面分析中经常出现。