Node Express中的并行异步路由器

时间:2017-08-21 14:27:18

标签: javascript node.js express routing

我有一个快速服务器,需要从每个请求的多个外部源获取一些数据。这个逻辑分成多个路由器(有些不是我管理的)。

这些路由器完全独立,因此无需等待另一台路由器。

作为一个例子,我有以下代码:

const router1 = express.Router();
const router2 = express.Router();
const router3 = express.Router();
const finalRouter = express.Router();

router1.use((req, res, next) => setTimeout(next, 2000));
router2.use((req, res, next) => setTimeout(next, 2000));
router3.use((req, res, next) => setTimeout(next, 2000));

finalRouter.use((req, res, next) => console.log('All done!'));

当我通常在我的应用程序中使用所有这些路由器时,它将按顺序执行并在6秒内打印All done!

但是为了提高我的页面速度,我想并行执行它们,所以它们都在2秒内完成。我怎么能这样做?

2 个答案:

答案 0 :(得分:1)

此处绝对不需要个别路线,您可以只使用一条路线并使用Promise.all等待所有请求。如果他们不能自然地支持Promises,你可以将它们包装在一个例如

router.use(async (req, res, next) => {
    await Promise.all([
       new Promise((resolve, reject) => {
           setTimeout(() => resolve(), 2000);
       }),
       ...
    ]);
    next();
});
router.use((req, res, next) => {
    console.log('All done!');
});

根据评论中的讨论,如果你没有能力将路线合并为一个 - 这很好,并不重要。想想更多关于这一点,你真正需要的是一个包装来捕捉"真正的"中间件,将其添加到队列,然后转到下一个。为了实现这一点,您至少需要访问设置路由(它看起来具有)的代码,例如。

<强> queue.js

module.exports = route => {
    return (req, res, next) => {
        // ensure we've got a queue
        if (!(req.queue instanceof Array)) {
            req.queue = [];
        }
        // queue the blocking route
        req.queue.push(new Promise((resolve, reject) => {
            // run real route, signal success or failure when done
            route(req, res, err => err ? reject(err) : resolve()); 
        });
        next(); // move on, don't wait
    };
}

然后在你的路线

const queue = require('./queue');
...
router.use(queue((req, res, next) => setTimeout(() => next(), 2000))));
router.use(queue((req, res, next) => setTimeout(() => next(), 2000))));
router.use(queue((req, res, next) => setTimeout(() => next(), 2000))));
router.use(async (req, res, next) => {
    await Promise.all(req.queue);
    console.log('All done!');
}

答案 1 :(得分:0)

您可以向所有子路由器发出虚假请求(通过滥用this回答中找到的内部句柄方法):

const mainroute = Express.Router();

mainroute.get("/",function(req,res,next){     
 Promise.all([
  new Promise(resolve => 
    router1.handle(req,res, resolve)),
  new Promise(resolve => 
    router2.handle(req,res,resolve))
  ]).then(_=>res.end("all done"));
});

也可以通过传递带有请求的promise数组手动实现,然后你可以在最后等待它们:

const router1 = express.Router();
const router2 = express.Router();

const timer = ms => new Promise( res => setTimeout(res,ms));

router1.use((req, res, next) =>{
  req.promises = [timer(2000)];
});      
router1.use( req => req.promises[0] = req.promises[0].then(_=>"first done"));

router2.use((req, res, next)=>req.promises.push(timer(2000)));

router1.use("/test",router2);
router1.use((req,res)=> Promise.all(req.promises).then(_=>res.end("all done")));