express 精讀

異彩發表於2019-01-12

tj.jpg
先上傳tj大神的照片,表示膜拜

剛知道,他是學設計的,剛知道他長得也這麼設計,也剛聽說,要想成為他一樣的大神,要讀原始碼。於是有了這篇文章。

express 框架

  • application, request, response, router 四大塊
  • 核心的思想是中介軟體,基礎是node的http模組
  • 中介軟體的基礎是 layer, 核心是router

application


express 返回的 createApplication方法,在當在應用層執行const app = express()的時候,返回的還是一個函式 function(req, res, next){ ... app.handle ...},application 的作用就是在app上掛載,自己封裝的request,response,mixin繼承proto, EventEmitter.prototype物件方法。

 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;
}
複製程式碼

中介軟體


  • application 的主要擴充套件在 proto,分析的時候主要抓住 app = handle(req, res, next)。由app.handle 到 router.handle,主要邏輯就在此。
  • node 模組http建立web服務類似 http.createServer(app).listen(80); 框架的重點是封裝app。app就是中介軟體的有序執行集合。
  • 什麼中介軟體的重點是 app.use 和 app[method]。
var express = require('./index');
var app = express();
// 宣告中介軟體
app.use(function cc(req,res,next){
console.log("111");
next();
})

app.get('/users', function(req, res, next) {
console.log(11111)
next();
}, function(req, res, next) {
console.log(22222)
next();
}, function(req, res, next) {
console.log(33333)
next();
}, function(req, res, next) {
console.log(44444)
res.send('hello world')
})

var server = app.listen(8081, function() {
var host = server.address().address
var port = server.address().port
console.log("應用例項,訪問地址為 http://%s:%s", host, port)
})
複製程式碼

列印中介軟體:

image.png

注意:前兩個中介軟體是框架自帶,第三個是use宣告的中介軟體,第四個是app[method]宣告的。

  • 有序執行是宣告的順序 和 next 方法。 next 有兩個 router/index.js 和 router/route.js 檔案中各有一個next
    • 第一個next是上圖中四個紅色箭頭指向的中介軟體依次執行的保證。
    • 第二個next是第四個箭頭中route.stack各個layer順序執行的保證。 app中的 res, req, next 就是這麼一個layer 傳到下一個layer。碰到route不等於undefined時候,在進入下一層 layer,直到最後一箇中介軟體,呼叫res.send 終結返回,完成一個http請求。

router.handle裡面 next() 函式是處理各種中介軟體的。while 迴圈遍歷 stack(初始化所有中介軟體的陣列)。遍歷出所有符合當前路由中介軟體(layer), next 一個一個處理,然後返回。

response / request


相對比較簡單,關鍵是看如何跟框架結合。

  • request.js 中 var req = Object.create(http.IncomingMessage.prototype); req 是基於node http模組當原型鏈重新宣告 req。又在req自身屬性上掛在一些自定義的常用到的方法。
  • 同理 response.js 中 var res = Object.create(http.ServerResponse.prototype); res 也是基於node http重新宣告的。掛在自己的常用函式。 application中。自己封裝的res, rep都是直接掛在到app靜態屬性上的。
    • 1: 是為了暴露出去,使用者可以自行擴充套件。
    • 2: 是為了柯里化,傳入到中介軟體中。 在每個宣告中介軟體 無論使用use 還是什麼app[method] 都需要先執行 lazyrouter
      image.png
      第一個use 預設的中介軟體是為了處理請求引數匹配路徑 第二個use 是為了初始化res和req
      image.png

注意:其實並沒有執行,只是先把app 傳過去,app上掛在了,res, rep 返回了一箇中介軟體,當使用者請求的時候,先去執行這個中介軟體。

image.png

感悟


分析別人原始碼,是習慣,先掌握主要脈絡反推使用者的框架思想,提升格局。在逐行分析,理解框架寫法的優雅。先抓大放小,再錙銖必較。

相關文章