next实现中间件的原理是什么?
发布于 8 年前 作者 yakczh 7208 次浏览 来自 问答

是不是把回调函数加到一个队列,每次取出来一个 运行当成当前的 next 运行 next(req,resp) 直到队列为空 ,那如果多个回调函数中如果要收集同一个数据,用什么方式组织起来呢? 按顺序 append ?

11 回复

没听懂你的需求,再描述一下?

@zstxt1989 没看懂你说的,请详解

挂在REQ上传输对象。因为REQ会被回收,只要不要跟原生方法重名都可以往上挂。

1.队列 当 app.use(handler) 的时候,会有一个队列存储handler,姑且取名为 stack 吧,每use一次就往statck中push。

2.处理 app开始处理请求,姑且假设是 app.handle() 吧,req,res对象是node传过来的,app可能会做一些处理,然后在 handle 内部会定义一个 next 方法,看起来大概这样子

function handle(req,res) {
	function next(){}
}

再加工一下,调用第一个中间件 function handle(req,res) { function next(){ var handler = statck[0]; handler(req,res,next) } next() }

可以看到,当调用stack队列中第一个handler的时候会把 next 函数作为第三个参数传递给handler。再稍微改造一下就可以实现next()调用下一个handler也就是中间件。

function handle(req,res) {
	var index=0;
	function next(){
		var handler = statck[index];
		index++;
		handler(req,res,next)
	}
	next()
}

大概就这个模型吧,之前大致了解过connect.js的处理过程,希望没错

@zstxt1989 我要收集某个数据, 比如每个中间件的内存占用, 中间件运行结束的内存占用- 进入中间件时的内存占用 收集的数据,怎么记录呢? 是不是这个函数要写成 function handle(req,res,next,memoryCollect) ?

@MiguelValentine 挂req,resp上可以, 但是这样名不符实啊,这个可能是业务中要用到的数据,跟req,resp没什么关系

@yakczh 收集的话你在入口文件里挂个对象{}就行了。但是你如果要收集单个中间件的内存占用。真的没有什么好的方法。因为JS对于内存分配与管理这一块几乎不可见。如果你能改源码或者用c/c++来做控制的话,那就另当别论了。

需要先执行 npm install flash-memory

var express = require("express");
var flash = require("flash-memory");
app.use('/', function (req, res, next){
  //app.flash = flash();
  //app.flash.add("fu.bx",'  你的值');
  flash().add("fu.bx", '你的值');
  next();
});
app.use('/', function(req,res,next){
  //app.flash.get('fu.bx');
  //app.flash.get('fu');
  console.log(flash().get('fu'));
  console.log(flash().get('fu.bx'));
});

flash-memory 是我写的一个单线程内,内存缓存模块化小模块; flash-memory-文档地址

  • 中间件就是一个个这样的函数 function (req, res, next) { }
  • 下一个中间件的执行是由上一个中间件显式地调用next()而驱动的,不是在同一个上下文内管理的
  • 所以中间件执行就像电流传导,导线相连,人只需要接上电源就行
  • 而电源的源头是 https://github.com/expressjs/express/blob/master/lib/router/index.js#L135
  • function next() 是定义在proto.handle也就是app.handle内的,因为req和res也在同一个域,所以next总是可以获得他们的应用传入下一个中间件

@flamingtop next function (req, res, next) { } 是不是应该再加一个参数 context
这样不同中间件之间需要数据交互的时候,可以通过context来读写数据

回到顶部