关于前端:express中间件原理connect

8次阅读

共计 2316 个字符,预计需要花费 6 分钟才能阅读完成。

不晓得用了 express.js 的你有没有这样的疑难:

  • app.use 为什么能够增加一个又一个中间件?
  • connect 是如何辨别一般中间件和谬误中间件的?
  • 中间件处理函数中的 next 指代的又是什么?

我简略看了一下 connect 源码,弄清楚了下面的这 3 个问题。

app.use 为什么能够增加一个又一个中间件?

app.use(function middleware1(req, res, next) {
  // middleware 1
  next();});
app.use(function middleware2(req, res, next) {
  // middleware 2
  next();});

connect 保护了一个 中间件栈(middleware stack)

数据结构:栈(stack)

每次调用 use,都会向这个利用 (app) 实例的栈 (stack) 推入一个带门路和处理函数的对象。

源码:

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;
};

connect 是如何辨别一般中间件和谬误中间件的?

// 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 正是通过中间件处理函数的形参长度来辨别出一般中间件和谬误中间件的。

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 的解释其实也懂了:

  • 跳过后面的所有谬误中间件:index 值是递增的,申请只走前面的谬误中间件
  • 跳过前面的非异样解决中间件:异样中间件两个条件都满足申请会进入,非异样中间件因为 hasError 为 true 因而申请不会进入

只能有一个异样解决中间件吗?
能够有多个。(官网文档 + 亲测)

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!});

中间件处理函数中的 next 指代的又是什么?

指代的是栈中的下一个中间件。

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 专栏:趁你还年老,做个优良的前端工程师

致力成为优良前端工程师!

正文完
 0