最近一直在學習如何用原生的 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到這里就結束了...
這么晚寫這文章,感覺寫了一大坨廢話...最后的執行順序才是我最想說的