您的位置:首页 > 移动开发

Express app.listen 函数了解

2016-05-21 22:43 501 查看
最近一直在学习如何用原生的 Node.js 来做一个网站。在写的同时也在学习 Express 源码。

一直觉得 Express 开启服务器的方法挺有趣的,就看了一下。

在 Express 运行的时候会默认运行根目录下的 index.js,里面的源码也很简单:

module.exports = require('./lib/express');

看到其实运行了
lib/express
模块,追踪过去,看到了:

exports = module.exports = createApplication;

导出了
createApplication
这个方法:

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

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

app.request = { __proto__: req, app: app };
app.response = { __proto__: res, app: app };
app.init();
return app;
}

首先定义了一个方法
app
,方法有三个参数
req
res
next
。然后在这个函数里面又执行了
app.handle
这个函数,这个函数后面说说,涉及到了路由。同时还涉及到了创建服务器函数,下面继续。

再往下看看,会看到
mixin
这个函数,在最上面引入模块的时候,定义了这个函数名:

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');

mixin
这个函数是引用了
merge-descriptors
模块,嗯,到
node_module
里面找找,或者到
github
里面找找也可以。

看源码,如果对原生JS的函数不是很熟悉的话,根本看不懂...不过我们可以到
MDN
里面查查,地址懒的贴。我也懒得去介绍里面的各种函数,这个模块的作用和
jQuery
里面的
$.extent
其实是一模一样的,将第二个参数的属性和属性值合并到第一个参数中,第三个参数如果是
false
则如果两个参数里面有属性一样,不允许覆盖,如果是
true
,则覆盖第一个参数属性。

由此可见:

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

这两句话就很好懂了,就是将
EventEmitter.prototype
proto
的属性克隆给
app


这里看到
proto
肯定也很郁闷...这玩意从哪里来的...还是往上面看:

var proto = require('./application');

额...又是一个模块,继续追踪,第一句话:

var app = exports = module.exports = {};

唉哟,又看到了
app
,这
express
命名也是有趣,都是
app
。我再看的时候也很郁闷,完全会看混淆。继续往下看,原来这个模块的作用就是给
app
添加了各种属性和函数,各种核心函数...各种看不懂的函数...

这里我们找到我们希望看到的一个
listen
这个函数:

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

好烦哟...又碰到看不懂的了,尼玛
this
是什么鬼!!!!我们从 Node.js 的 API 手册可以看到啊,明明官方都说了:

The requestListener is a function which is automatically added to the 'request' event.

this
这个参数的位置明明应该是一个函数啊,但是在
application
里面我们看到的
app
很显然就是一个
{}
对象啊,尼玛,怎么可能是一个
Function
?

好吧,没办法,我们
console.log(this)
试试,看看返回的是什么:

{ [Function]
domain: undefined,
_events: { mount: [Function: onmount] },
_maxListeners: undefined,
setMaxListeners: [Function: setMaxListeners],
getMaxListeners: [Function: getMaxListeners],
emit: [Function: emit],
addListener: [Function: addListener],
on: [Function: addListener],
once: [Function: once],
removeListener: [Function: removeListener],
removeAllListeners: [Function: removeAllListeners],
listeners: [Function: listeners],
listenerCount: [Function: listenerCount],
init: [Function: init],
defaultConfiguration: [Function: defaultConfiguration],
lazyrouter: [Function: lazyrouter],
handle: [Function: handle],
use: [Function: use],
route: [Function: route],
...

第一句居然是
Function
,是什么鬼?什么时候变成了
Function
,仔细看一下,我们发现里面好像有
EventEmitter.prototype
的属性:

EventEmitter {
domain: undefined,
_events: undefined,
_maxListeners: undefined,
setMaxListeners: [Function: setMaxListeners],
getMaxListeners: [Function: getMaxListeners],
emit: [Function: emit],
addListener: [Function: addListener],
on: [Function: addListener],
once: [Function: once],
removeListener: [Function: removeListener],
removeAllListeners: [Function: removeAllListeners],
listeners: [Function: listeners],
listenerCount: [Function: listenerCount] }

哎哟,不错哟,貌似发现了新大陆...明明在
application
这个模块没有添加这个属性啊,从哪里加的?这个时候我们应该顺其自然的想到了:

mixin(app, EventEmitter.prototype, false);

这句话,好像很突然的想到似的...是否在想明明在
express
这个模块加的,为啥在
application
里面会添加进去?OK,到了我们最关键的时候了,我们应该把
Express
的执行顺序理清楚了:

在 CMD 或者 终端 执行:node app

在我们自己写的
app.js
文件中执行
express()
,这里就开始运行
express
模块了。

进去
express
模块,运行
index.js


index.js
进去
lib/express.js


express.js
中执行
createApplication


createApplication
中首先定义了一个
app
的函数,其实刚才我们
console.log(this)
的时候,
this
返回的就是这个
app
函数

然后通过
mixin(app, EventEmitter.prototype, false);mixin(app, proto, false);
EventEmitter.prototype
proto
里面的属性全部都加到
app
这个函数里面

执行
app.request
app.response
这两个就是将重新定义的
request
response
加到
app
里面,这两个以后再说

继续执行
app.init();
,这句话就简单了啊,
init
这个函数在
application.js
模块中,主要作用就是给
app
加一些初始化设置

最后返回
app


在我们自己写的
app.js
文件中获取到返回的
app
,准备创建服务器
app.listen(3000)


开始执行
app.listen
这个函数,在
app
中找到
listen
,这个函数在
express.js
中已经从
proto
克隆到了
app
上了,所以,我们直接到
proto
中找
listen
,也就是
application.js
中去找,找到之后就回到了我们最开始的问题:
var server = http.createServer(this);
this
是什么????看到这里,其实我们已经知道了,
this
其实就是
var app = function(req,res,next){}
,OK到这里就结束了...

这么晚写这文章,感觉写了一大坨废话...最后的执行顺序才是我最想说的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: