不知道用了express.js的你有沒有這樣的疑問:前端
我簡單看了一下connect源碼,弄清楚了上面的這3個問題。git
app.use(function middleware1(req, res, next) { // middleware 1 next(); }); app.use(function middleware2(req, res, next) { // middleware 2 next(); });
connect維護了一個中間件棧(middleware stack)github
數據結構:棧(stack)express
每次調用use,都會向這個應用(app)實例的棧(stack)推入一個帶路徑和處理函數的對象。segmentfault
源碼:瀏覽器
function createServer() { function app(req, res, next){ app.handle(req, res, next); } // ... app.stack = []; // 注意這裏 return app; } proto.use = function use(route, fn) { var handle = fn; var path = route; // ... // add the middleware this.stack.push({ route: path, handle: handle }); return this; };
// regular middleware app.use(function (req, res, next) { next(new Error('boom!')); }); // error middleware app.use(function onerror(err, req, res, next) { // an error occurred! });
JavaScript的函數的長度屬性:length。微信
這麼說可能比較繞,看下面這個例子就懂了。前端工程師
例如數據結構
function test1(foo,bar){ } test.length // 2 function test2(foo,bar,baz){ } test.length // 3
connect正是經過中間件處理函數的形參長度來區分出普通中間件和錯誤中間件的。app
function call(handle, route, err, req, res, next) { var arity = handle.length; var error = err; var hasError = Boolean(err); try { if (hasError && arity === 4) { // error-handling middleware handle(err, req, res, next); return; } else if (!hasError && arity < 4) { // request-handling middleware handle(req, res, next); return; } } catch (e) { // replace the error error = e; } // continue next(error); }
看了源碼,官方文檔對錯誤處理中間件描述skipping any error middleware above that middleware and any non-error middleware below
的解釋其實也懂了:
只能有一個異常處理中間件嗎?
能夠有多個。(官方文檔+親測)
app.use(logErrors) app.use(clientErrorHandler) app.use(errorHandler)
// error middleware one app.use(function onerror(err, req, res, next) { // an error occurred! next(err) // 注意要這麼寫,next()進入不到下一個異常處理中間件 }); // error middleware two app.use(function onerror(err, req, res, next) { // an error occurred! });
指代的是棧中的下一個中間件。
proto.handle = function handle(req, res, out) { var index = 0; var stack = this.stack; // ... function next(err) { // next callback var layer = stack[index++]; // call the layer handle call(layer.handle, route, err, req, res, next); } next(); };
經過上面代碼能夠看出,每次調用next()函數,會執行index++,layer爲middleware stack中的下一個中間件。
其中layer.handle來自於this.stack.push({ route: path, handle: handle });
。
期待和你們交流,共同進步,歡迎你們加入我建立的與前端開發密切相關的技術討論小組:
- 微信公衆號: 生活在瀏覽器裏的咱們 / excellent_developers
- Github博客: 趁你還年輕233的我的博客
- SegmentFault專欄:趁你還年輕,作個優秀的前端工程師
努力成爲優秀前端工程師!