Express中間件的原理及實現


在Node開發中免不了要使用框架,比如expresskoakoa2拿使用的最多的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(響應)回去而這個服務端處理的過程就有文章可做了,想象一下當業務邏輯復雜的時候,為了明確和便於維護,需要把處理的事情分一下,分配成幾個部分來做,而每個部分就是一個中間件
node.js - express 框架中的app.use是什么作用? - SegmentFault
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內部維護的一個函數數組中去測試結果:
 
 
ok,相信對Express中間件的原理已經有所了解了,koa和koa2中間件的原理其實也是一樣的




轉自:https://www.jianshu.com/p/797a4e38fe77


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM