不知道用了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专栏:趁你还年轻,作个优秀的前端工程师
努力成为优秀前端工程师!