阅读connect&express&socket.io源码遇到的问题
发布于 9 年前 作者 mtaa 3570 次浏览 来自 问答
// all done
if (!layer) {
 defer(done, err); // ????? 为什么这里要用defer异步调用回调函数done?
 return;
}

上面代码是connect.js中handle函数的代码,layer中间件运行完之后由defer异步调用最后的回调函数done。 express.js和socket.io中也是类似这样调用的,区别是express.js直接用的setImmediate,socket.io里用的process.nextTick

在connect.js的代码历史中,只注释了这么一句: Correctly invoke async callback asynchronously

setImmediateprocess.nextTick的区别我能搞清楚,这里我的问题是为什么这里要异步调用?直接done(err)有什么不好的地方吗?我试过注释这句话直接调用,重跑了测试用例也没发现问题。

下面是链接和相关代码:

#L151

/* istanbul ignore next */
var defer = typeof setImmediate === 'function'
 ? setImmediate
 : function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) }
/**
 * Handle server requests, punting them down
 * the middleware stack.
 *
 * @private
 */
proto.handle = function handle(req, res, out) {
 var index = 0;
 var stack = this.stack;
 // final function handler
 var done = out || finalhandler(req, res, {
 env: env,
 onerror: logerror
 });
 
 function next(err) {
 // next callback
 var layer = stack[index++];
 // all done
 if (!layer) {
 defer(done, err); // ????? 为什么这里要用defer异步调用done函数?
 return;
 }
 // route data
 var path = parseUrl(req).pathname || '/';
 var route = layer.route;
	
 // call the layer handle
 call(layer.handle, route, err, req, res, next);
 }
 next();
};
3 回复

用户在某个中间件里调用 next() ,而 next 执行后又没有能与 url 规则匹配上的中间件时,done(err) 才会执行, 比如:

var app = connect();
app.use('/api', (req, res, next) => {
 console.log('hello world');
 next();
});
app.use('/other/api', () => {
 console.log('no invoke here !!!');
})

当你请求 url 为 /api/xxx 时,第一个中间件会执行,在第一个中间件里面调用 next() 后, connect 的 中间件 stack 剩余的数组里并没有 与 /api/test 能匹配上的中间件,此时 done(err) 会执行,

done 的作用是在调用 next 后,后面没有任何能匹配上的中间件时,connect帮你响应一个 404 Not Found.

这里当然可以不需要调用 setImmediate 或 process.nextTick,

但是代价是:

任何匹配不上中间件路由规则的 http 请求,connect 都是会即时响应404,而不会及时让出 cpu 时间来让 connect 来优先处理其他请求。 setImmediate / process.nextTick 可以让这次匹配不上中间件的请求 (业务层面你可以认为是一个无效请求),响应时机推后,而让 node 主线程快速处理新的 http 请求。

另外你真的懂 setImmediate / process.nextTick 吗? 可以参考这篇文章:https://github.com/vincentLiuxiang/mybook

@vincentLiuxiang 谢谢,回复晚了,早先看到忘记回复了。我当时想不明白为啥要用defer,不知道有啥好处,你一说『让 node 主线程快速处理新的 http 请求』,我就明白了,谢谢。

中间件遍历方式优化 easy-websocket

这文章学习了,最近也在写基于websocket,类似connect的中间件框架,还不完善,有问题可以再联系你吗? jsonrpc.io

==== 我又去找资料发现这篇分析setImmediate,process.nextTick的文章居然是我自己写的,是以前帐号写的。 https://cnodejs.org/topic/5556efce7cabb7b45ee6bcac

!!!- -

@mtaa 加油,有问题随时 @ 我,https://github.com/vincentLiuxiang/easy-websocket 这个库是我自己基于 node.js 实现的 websocket, 代码比较精简,适合深入了解 websocket 内部原理

回到顶部

AltStyle によって変換されたページ (->オリジナル) /