CNode

express中间件的问题

问答
Kkeller35发布于11 年前最后回复11 年前11 回复7591 浏览0 收藏

开发express中间件的时候遇到一个问题: 代码如下:

app.use(function(req, res, next){ next(); console.log("after next"); }); app.use(function(req, res, next){ console.log("before next"); next(); });

这里的中间件调用结果是:

before next after next

所以我认为中间件是一个栈结构,next前的代码先执行,然后执行next调用下一个中间件,最后回到当前的中间件,执行next后面的代码。 但是我写了另外一个例子,并不支持我这种理解。 代码如下:

app.use(function(req, res, next){ next(); console.log("after next") }); app.use(function(req, res, next){ process.nextTick(function(){ console.log("before next") next(); }); });

执行结果:

after next before next

请问这是什么原因?

查看回复

回复 (11)

H
holyselina#1·11 年前

当前next栈结构只是同步执行的,这里的异步的代码要到等到下次nextTick事件执行,只有一个线程,一次只能执行一个事件

C
Chensonghao#2·11 年前

理解nextTick的机制你就明白了

K
klesh#3·11 年前

next 是同步的 nextTick 是异步的,也就是会等到当前所有同步操作完成之后才有机会轮到它。

K
keller35#4·11 年前
引用 holyselina当前next栈结构只是同步执行的,这里的异步的代码要到等到下次nextTick事件执行,只有一个线程,一次只能执行一个事件

@holyselina 中间件的栈结构也是需要调用next才执行的,而我在异步操作中调用next,按道理也是顺序执行中间件,为什么就不对了,这个地方能解释下吗?

K
keller35#5·11 年前
引用 kleshnext 是同步的 nextTick 是异步的,也就是会等到当前所有同步操作完成之后才有机会轮到它。

@klesh 嗯,我知道nextTick是异步的,但是我的next也是在异步操作中调用的

K
klesh#6·11 年前
引用 keller35@klesh 嗯,我知道nextTick是异步的,但是我的next也是在异步操作中调用的

@keller35 啊? ... 首先,想像虚拟机是一个环回系统,js 代码就一个队例,虚拟机不停地从队例中取出“一段同步”代码。执行,完成后又去队例中取出另一段代码,执行。。。直到队列清空,程序就退出了。当然,每次执行又可能产出新的一段“代码”插入到队列中,这样程序就一直地运行下去。

第一个 next 执行后,是去到 nextTick 对吧,但是所有一切在nexTick中的代码这个时候都不会执行,而是被插入到队例后面。然后程序继续往下走,就执行了 console.log("after next")。然后本次“同步”代码全部执行完了,虚拟机进入下一次循环,这时 nextTick 中的代码才会被执行。

K
keller35#7·11 年前
引用 klesh@keller35 啊? ... 首先,想像虚拟机是一个环回系统,js 代码就一个队例,虚拟机不停地从队例中取出“一段同步”代码。执行,完成后又去队例中取出另一段代码,执行。。。直到队列清空,...

@klesh 嗯,谢谢你的回答! 你所说的我都明白,event loop我也理解。 但是我不理解的地方是:next作为下一个中间件的调用函数,需要调用了代码才会执行到下一个中间件。而这里是还未调用next的时候,就先执行了console.log(“after next”)?

K
klesh#8·11 年前
引用 keller35@klesh 嗯,谢谢你的回答! 你所说的我都明白,event loop我也理解。 但是我不理解的地方是:next作为下一个中间件的调用函数,需要调用了代码才会执行到下一个中间件。而这里是还未...

@keller35 你……,真的明白吗?哎,next不是未调用,事实上第一个next函数绝对是正常调用了,这时候就转到第二个 use ,其中传给nextTick的函数 不会马上执行,process.nextTick只是把这个函数插入 event loop,而不是马上执行这个函数。插完函数就立即返回了,这个时候就回到第一个 use 中执行 console.log("after next")。到了这个点,本次 loop 才完成,之后才会把刚才插入的函数拿出来执行,打印出 before next 。

W
William17#9·11 年前

你把next()理解错了. express的next()跟koajs的yield next是不一样的...

app.use(function A(req, res, next){
	next();
	console.log(“after next”)
});
app.use(function B(req, res, next){
	process.nextTick(function(){
		console.log(“before next”)
		next();
	});
});
app.use(function C(req, res, next) {
	//
});
// N ∈N+
app.use(function(req, res, next) {
   // event loop N: A-start
   // event loop N: B-start
   process.nextTick(function(){
     // event loop N+1: 
	 console.log(“before next”);
	 // event loop N+1: C-start
	 // ...
	 // event loop N+1: C-end
  });
   // event loop N:  B-end
   console.log(“after next”);
  // event loop N :  A-end
})

K
keller35#10·11 年前
引用 William17你把next()理解错了. express的next()跟koajs的yield next是不一样的...

@William17 嗯,谢谢你的回答。 是我把next理解错了,看了你的第二段代码就明白了。 那可否简单说一下koa的next有什么不同?

W
William17#11·11 年前
// yield next;
// 如果下一个中间件通过yield执行一些异步操作,那下面的console.log将会在异步操作之后才被执行


// next();
// 假如下一中间件有异步代码,下面的console.log总会在异步代码执行之前执行
console.log("after");
参与回复
登录后即可参与回复。登录