我在尝试处理来自客户端的多个请求时遇到问题。通过权利,每条路线都应该异步处理,但是我不能在请求之后处理请求,而前一条路由阻止下一条路由。使用以下代码我使用promises并使用Express.js路由器
let api = Router();
api.get('/a', (req, res, next) => {
console.log('A: get all A');
getAllA()
.then(() => console.log('A: finish retrieving A'));
console.log('A: do something else');
});
api.get('/b', (req, res, next) => {
console.log('B: get all B');
getAllB()
.then(() => console.log('B: finish retrieving B')
console.log('B: do something else');
});
因此,如果我几乎立即请求 / a 然后 / b ,则输出目前为:
// Request /a
'A: get all A'
'A: do something else'
// Request /b
'A: finish retrieving A'
'B: get all B'
'B: do something else'
'B: finish retrieving B'
虽然我期待它是这样的:
// Request /a
'A: get all A'
'A: do something else'
// Request /b
'B: get all B'
'B: do something else'
'A: finish retrieving A'
'B: finish retrieving B'
是否有预期或有其他方法可以解决这个问题?
答案 0 :(得分:3)
node.js服务器一次只运行一个Javascript执行线程。它实际上并不是在同一时间处理多个请求。因此,如果一个请求占用CPU一段时间,则在第一个请求完成并放弃CPU之前,不会处理任何其他请求。
但是,如果您的请求执行异步操作(异步文件I / O,异步网络,设置定时器以便将来执行某些操作,请使用一些实现其他异步操作的第三方库等等),那么每当请求启动异步操作并将控制权返回给事件队列,然后另一个请求可以开始处理,直到它完成或同时执行异步操作。它是否完全取决于事物的时间安排。通过这种方式,多个请求可以同时“在飞行中”,即使只有一个请求实际上一次运行Javascript。
因此,在您的代码中,它实际上取决于getAllA()
和getAllB()
正在做什么。如果它们是同步操作,那么它们将在运行时阻止其他线程。如果它们是异步操作,但它们满足相同的资源(例如数据库或文件或服务器),那么它们可能仍然会导致某些序列化,因为它们依赖于外部资源的可用性。
在node.js中获得真正的并行请求处理的一种方法是使用群集。使用node.js群集,您可以在同一台计算机上启动多个node.js进程(通常与您拥有的CPU核心数量大致相同),然后每个node.js进程可以独立地并行处理请求。如果您拥有群集中所有进程必须访问的共享资源,那么您仍然必须找到一种方法来跨进程共享这些资源(数据库,共享信息的自定义中央存储库,redis等等。)。
例如,如果你做了类似这样的事情,你可以在同一时间看到多个飞行请求:
let api = Router();
api.get('/a', (req, res, next) => {
console.log('start of a');
setTimeout(function() {
console.log('done with a');
res.json({status: "ok", msg: "done with a"});
}, 500);
});
api.get('/b', (req, res, next) => {
console.log('start of b');
setTimeout(function() {
console.log('done with b');
res.json({status: "ok", msg: "done with b"});
}, 500);
});
如果你然后一个接一个地关闭/ a和for / b的请求,你应该在服务器控制台中得到它:
start of a
start of b
done with a
done with b
这两个请求同时“在飞行中”,但实际上并不是在同时执行Javascript。注意:我使用setTimeout()
来模拟具有已知且可控制的响应时间的异步操作。这可以是任何系列的异步操作。