最近在學習的內容裏面有關於中間件原理以及實現,認真瞭解一下,發現其原理並不難
轉一篇寫得不錯的文章做下記錄, 轉載地址:https://www.jianshu.com/p/797a4e38fe77
GitHub,歡迎star:https://github.com/BadWaka/node-express-middleware-study
在Node開發中免不了要使用框架,比如express
、koa
、koa2
拿使用的最多的express
來舉例子
開發中肯定會用到很多類似於下面的這種代碼
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
一個請求發送到服務器後,它的生命週期是 先收到request(請求),然後服務端處理,處理完了以後發送response(響應)回去
而這個服務端處理的過程就有文章可做了,想象一下當業務邏輯複雜的時候,爲了明確和便於維護,需要把處理的事情分一下,分配成幾個部分來做,而每個部分就是一箇中間件
app.use 加載用於處理http請求的middleware(中間件),當一個請求來的時候,會依次被這些 middlewares處理。
中間件執行的順序是你定義的順序
那中間件到底是個什麼東西呢?
中間件其是一個函數,在響應發送之前對請求進行一些操作
function middleware(req,res,next){
// 做該乾的事
// 做完後調用下一個函數
next();
}
這個函數有些不太一樣,它還有一個next參數,而這個next也是一個函數,它表示函數數組中的下一個函數
那函數數組又是什麼呢
express內部維護一個函數數組,這個函數數組表示在發出響應之前要執行的所有函數,也就是中間件數組
使用app.use(fn)
後,傳進來的fn
就會被扔到這個數組裏,執行完畢後調用next()
方法執行函數數組裏的下一個函數,如果沒有調用next()
的話,就不會調用下一個函數了,也就是說調用就會被終止
Express中間件的使用
理論部分簡單的說了一下,現在來用代碼驗證一下,注意需要安裝一下express
/**
* express中間件的實現和執行順序
*
* 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);
輸出結果:
可以看到在執行完下一個函數後又會回到之前的函數執行next()
之後的部分
這可以理解爲中間件的一個特性吧
現在可以說已經明白Express的中間件是什麼了,以及app.use的用法了,下面就來自己實現一下吧
實現簡單的Express中間件
/**
* 仿照express實現中間件的功能
*
* Created by BadWaka on 2017/3/6.
*/
var http = require('http');
/**
* 仿express實現中間件機制
*
* @return {app}
*/
function express() {
var funcs = []; // 待執行的函數數組
var app = function (req, res) {
var i = 0;
function next() {
var task = funcs[i++]; // 取出函數數組裏的下一個函數
if (!task) { // 如果函數不存在,return
return;
}
task(req, res, next); // 否則,執行下一個函數
}
next();
}
/**
* use方法就是把函數添加到函數數組中
* @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這個函數添加了一個use方法,函數也是可以有屬性的
原理就是每調用一次use,就把傳進來的函數扔到express內部維護的一個函數數組中去
測試結果:
作者:waka
鏈接:https://www.jianshu.com/p/797a4e38fe77
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯繫作者獲得授權並註明出處。