Express中間件的原理及實現(xiàn)

參考文章:初學nodejs一:別被Express的API搞暈了

GitHub环础,歡迎star:https://github.com/BadWaka/node-express-middleware-study

在Node開發(fā)中免不了要使用框架,比如express宏侍、koakoa2

拿使用的最多的express來舉例子

開發(fā)中肯定會用到很多類似于下面的這種代碼

var express = require('express');
var app = express();
app.listen(3000, function () {
    console.log('listen 3000...');
});

app.use(middlewareA);
app.use(middlewareB);
app.use(middlewareC);

對我要說的就是app.use()

為什么要說這個蜀漆?因為面試時被問到了谅河。。。

哦 你用過Express啊 來來來 那你說說app.use的原理是什么绷耍?

一臉懵逼...0.0

app.use()就是通常所說的使用中間件

那中間件是什么呢?它又有啥用呢褂始?

中間件 middleware

一個請求發(fā)送到服務(wù)器后诸典,它的生命周期是 先收到request(請求),然后服務(wù)端處理狐粱,處理完了以后發(fā)送response(響應(yīng))回去

而這個服務(wù)端處理的過程就有文章可做了,想象一下當業(yè)務(wù)邏輯復(fù)雜的時候判莉,為了明確和便于維護,需要把處理的事情分一下踩叭,分配成幾個部分來做容贝,而每個部分就是一個中間件

node.js - express 框架中的app.use是什么作用? - SegmentFault

app.use 加載用于處理http請求的middleware(中間件)焕参,當一個請求來的時候航厚,會依次被這些 middlewares處理幔睬。

中間件執(zhí)行的順序是你定義的順序

那中間件到底是個什么東西呢摹芙?

中間件其是一個函數(shù)盈电,在響應(yīng)發(fā)送之前對請求進行一些操作

function middleware(req,res,next){
    // 做該干的事

    // 做完后調(diào)用下一個函數(shù)
    next();
}

這個函數(shù)有些不太一樣,它還有一個next參數(shù)田篇,而這個next也是一個函數(shù),它表示函數(shù)數(shù)組中的下一個函數(shù)

那函數(shù)數(shù)組又是什么呢

express內(nèi)部維護一個函數(shù)數(shù)組坡疼,這個函數(shù)數(shù)組表示在發(fā)出響應(yīng)之前要執(zhí)行的所有函數(shù)彬呻,也就是中間件數(shù)組

使用app.use(fn)后,傳進來的fn就會被扔到這個數(shù)組里柄瑰,執(zhí)行完畢后調(diào)用next()方法執(zhí)行函數(shù)數(shù)組里的下一個函數(shù)闸氮,如果沒有調(diào)用next()的話,就不會調(diào)用下一個函數(shù)了教沾,也就是說調(diào)用就會被終止

Express中間件的使用

理論部分簡單的說了一下蒲跨,現(xiàn)在來用代碼驗證一下,注意需要安裝一下express

/**
 * express中間件的實現(xiàn)和執(zhí)行順序
 *
 * Created by BadWaka on 2017/3/6.
 */
var express = require('express');

var app = express();
app.listen(3000, function () {
    console.log('listen 3000...');
});

function middlewareA(req, res, next) {
    console.log('middlewareA before next()');
    next();
    console.log('middlewareA after next()');
}

function middlewareB(req, res, next) {
    console.log('middlewareB before next()');
    next();
    console.log('middlewareB after next()');
}

function middlewareC(req, res, next) {
    console.log('middlewareC before next()');
    next();
    console.log('middlewareC after next()');
}

app.use(middlewareA);
app.use(middlewareB);
app.use(middlewareC);

輸出結(jié)果:


可以看到在執(zhí)行完下一個函數(shù)后又會回到之前的函數(shù)執(zhí)行next()之后的部分
這可以理解為中間件的一個特性吧

現(xiàn)在可以說已經(jīng)明白Express的中間件是什么了授翻,以及app.use的用法了或悲,下面就來自己實現(xiàn)一下吧

實現(xiàn)簡單的Express中間件

/**
 * 仿照express實現(xiàn)中間件的功能
 *
 * Created by BadWaka on 2017/3/6.
 */

var http = require('http');

/**
 * 仿express實現(xiàn)中間件機制
 *
 * @return {app}
 */
function express() {

    var funcs = []; // 待執(zhí)行的函數(shù)數(shù)組

    var app = function (req, res) {
        var i = 0;

        function next() {
            var task = funcs[i++];  // 取出函數(shù)數(shù)組里的下一個函數(shù)
            if (!task) {    // 如果函數(shù)不存在,return
                return;
            }
            task(req, res, next);   // 否則,執(zhí)行下一個函數(shù)
        }

        next();
    }

    /**
     * use方法就是把函數(shù)添加到函數(shù)數(shù)組中
     * @param task
     */
    app.use = function (task) {
        funcs.push(task);
    }

    return app;    // 返回實例
}

// 下面是測試case

var app = express();
http.createServer(app).listen('3000', function () {
    console.log('listening 3000....');
});

function middlewareA(req, res, next) {
    console.log('middlewareA before next()');
    next();
    console.log('middlewareA after next()');
}

function middlewareB(req, res, next) {
    console.log('middlewareB before next()');
    next();
    console.log('middlewareB after next()');
}

function middlewareC(req, res, next) {
    console.log('middlewareC before next()');
    next();
    console.log('middlewareC after next()');
}

app.use(middlewareA);
app.use(middlewareB);
app.use(middlewareC);

JS是一門神奇的語言,這里用到了兩個閉包堪唐,并且給app這個函數(shù)添加了一個use方法巡语,函數(shù)也是可以有屬性的

原理就是每調(diào)用一次use,就把傳進來的函數(shù)扔到express內(nèi)部維護的一個函數(shù)數(shù)組中去

測試結(jié)果:


ok淮菠,相信對Express中間件的原理已經(jīng)有所了解了男公,koa和koa2中間件的原理其實也是一樣的

繼續(xù)去看源碼了。合陵。枢赔。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市拥知,隨后出現(xiàn)的幾起案子踏拜,更是在濱河造成了極大的恐慌,老刑警劉巖低剔,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件速梗,死亡現(xiàn)場離奇詭異,居然都是意外死亡户侥,警方通過查閱死者的電腦和手機镀琉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蕊唐,“玉大人屋摔,你說我怎么就攤上這事√胬妫” “怎么了钓试?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵装黑,是天一觀的道長。 經(jīng)常有香客問我弓熏,道長恋谭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任挽鞠,我火速辦了婚禮疚颊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘信认。我一直安慰自己材义,他們只是感情好,可當我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布嫁赏。 她就那樣靜靜地躺著其掂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪潦蝇。 梳的紋絲不亂的頭發(fā)上款熬,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天,我揣著相機與錄音攘乒,去河邊找鬼贤牛。 笑死,一個胖子當著我的面吹牛持灰,可吹牛的內(nèi)容都是我干的盔夜。 我是一名探鬼主播负饲,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼堤魁,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了返十?” 一聲冷哼從身側(cè)響起妥泉,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎洞坑,沒想到半個月后盲链,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡迟杂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年刽沾,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片排拷。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡侧漓,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出监氢,到底是詐尸還是另有隱情布蔗,我是刑警寧澤藤违,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站纵揍,受9級特大地震影響顿乒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜泽谨,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一璧榄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧吧雹,春花似錦犹菱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至龙亲,卻和暖如春陕凹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鳄炉。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工杜耙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人拂盯。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓佑女,卻偏偏與公主長得像,于是被迫代替她去往敵國和親谈竿。 傳聞我的和親對象是個殘疾皇子团驱,可洞房花燭夜當晚...
    茶點故事閱讀 45,440評論 2 359

推薦閱讀更多精彩內(nèi)容