GitHub环础,歡迎star:https://github.com/BadWaka/node-express-middleware-study
在Node開發(fā)中免不了要使用框架,比如express
宏侍、koa
、koa2
拿使用的最多的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ù)雜的時候判莉,為了明確和便于維護,需要把處理的事情分一下踩叭,分配成幾個部分來做容贝,而每個部分就是一個中間件
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ù)去看源碼了。合陵。枢赔。