.1-淺析express源碼之入口文件

来源:https://www.cnblogs.com/QH-Jimmy/archive/2018/04/13/8818028.html
-Advertisement-
Play Games

鴿了鴿了,webpack源碼大垃圾,看了那麼久,感覺自己越來越渣……還是換個口味,node瞭解一下? 嘗試從express框架源碼入手,學習一下node的http模塊相關的知識。 入口文件 先從框架的主文件入手,該JS文件包含三大部分: 1、外部/工具模塊引入與屬性掛載 2、主函數定義 3、中間件的 ...


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

4.18後記,補充一下這裡的知識點:

  這裡返回函數是必要的,首先參照正常情況下創建node伺服器的代碼:

let http = require('http');
http.createServer((req, res) => {
    // ...
}).listen(9123);

  可以看出,第二步的方法調用接受一個函數,通常我們會在這處理請求併進行響應。

  而app.listen方法(這裡提前講一下)的代碼如下:

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

  可以看到,基本上就是原生的方法,對應傳進去的函數變成了this,this指向什麼呢?就是生成的函數,當有請求時,觸發的函數就是app.handle方法。

  涉及的handle、init方法均來源於混入的proto中,這個後面再看。

 

  第三塊就是4.x的一個變化:Express 4 不再依賴 Connect,而且從內核中移除了除 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模塊,看來還是不能完全脫離,偷偷用了一個。

 

  完結。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 使用的模塊 ws http http-proxy 主要通過htt-proxy實現中轉 啟動websocket服務 ws http http-proxy 啟動http-proxy代理伺服器 註意:客戶端發送的數據websocket已加密無法直接獲得,該演示通過ws模塊中的PerMessageDefla ...
  • 今天為什麼要給大家分享這篇文章呢,我發現最近來學前端的特別多,群裡面整天都有人問:前端好找工作嗎?前端要怎麼學啊?前端工資怎麼樣?前端XX,前端XXX,雖然我回答過無數次這種問題了,但是問這個的還是有很多,今天我就給大伙分享一下前端學習路線,當然不是我自己總結的,畢竟沒有那麼厲害,就借用騰訊大佬的給 ...
  • 之前用vue-cli腳手架在windows上開發的一個項目,現在有換mac的打算,但是換系統的話對代碼對環境依賴比較嚴重。 去年和別的FE並行開發兩個人用的都是windows,這樣還好,沒有什麼問題,但是兩個人電腦環境不一樣問題就比較多了。 所以準備將環境切換到Linux,但是遇見了重重困難,這裡記 ...
  • vue中methods,computed,watch方法的區別 ...
  • 語法: 子組件: 給子組件弄個名字,name。props用來聲明從父組件傳來的數據。其他html和css部分正常寫。 父組件: HTML部分:使用子組件name作為標簽來顯示子組件。:items=“item”,是將數據傳給子組件。items是在子組件聲明的,item是父組件中data返回的。 js部 ...
  • 自從年前得空寫了兩篇文章之後就開始忙了,這一忙就是2個月
  • 系統描述:用戶與管理員客服聊天,當用戶在五分鐘之內不說話,則客服會在5分鐘後斷開。當直接關閉瀏覽器頁面時,後臺管理員就無法檢測到這種狀態,此用戶無法從管理員的服務列表裡面清除 onunload和onbeforeunload這兩個事件可以在瀏覽器關閉或者刷新時調用 可以在<script>腳本中通過 w ...
  • 1 1、開發環境搭建 2 1) 版本控制工具 3 svn 和 git 4 5 2) 下載安裝 nodeJS 和 npm 6 7 3) 在開發工具 (Hbuilder) 中配置 cmd 終端,通過終端安裝 Babel 編譯器 8 1.初始化項目 9 在安裝Babel之前,需要用npm init... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...