Express.js: 发送响应及执行后台任务

4
在 Express.js 中,我想在发送响应后执行一个任务。
然而,我希望尽可能快地返回响应时间。 我不需要将此任务的结果返回给客户端,因此我正在尝试立即返回响应。
该任务不是 CPU 密集型,因此事件循环不会被卡住。
因此,这是我的后台任务:
function backgroundTask() {
   return new Promise(resolve => setTimeout(() => {
      console.log("backgroundTask finished");
      resolve();
   }, 1000));
}

我的第一次尝试是直接调用backgroundTask函数:

app.post('/messages', async function (req, res) {
  res.status(200).send({ success: true });
  performBackgroundTasks();
});

第二种尝试是将backgroundTask函数调用放入setTimeout()中:
app.post('/messages', async function (req, res) {
  res.status(200).send({ success: true });
  setTimeout(() => performBackgroundTasks(), 0);
});

问题是:最好的方法是什么,以确保响应发送到客户端并在后台执行任务?
附注:我知道“最佳方法”是使用Worker Threads,但我只需要一种简单的方法来执行后台任务。
4个回答

7
你可以使用“finish”事件:
app.use((req, res, next) => {
    res.on('finish', () => {
        console.log('Response has been sent!')
        performBackgroundTasks();
    })
    next()
})

1
这似乎适用于所有路由。有没有办法只在特定的路由上应用它? - Aniket Kariya
2
你可以直接在特定路由的代码中调用 res.on('finish', () => {}) - Rashomon

2
你可以将该函数转换为中间件,在响应后调用next()。

一个例子会很好。 - Aniket Kariya

1
你的第一次和第二次尝试都非常适合你的用例。如果你的任务不是CPU密集型,使用“工作线程”甚至不如你的两种方法更好。

1
我很高兴你提到最好的方法是生成一个Worker Thread,因为确实如此。我认为你正在尝试做一些根本不应该做的事情。从express发送res应该是该过程的最终停靠点,并且它应该包含有关整个作业成功的详细信息,因此继续进行将剥夺您的应用程序执行该操作的能力。至少在返回前端之前不会。
如果第二步对用户体验不重要,为什么不在第一个res中返回,并在前端的promise return中触发另一个express调用?
抱歉,我相信你有一个很好的理由,也许你可以详细说明为什么这是你需要采取的路线...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接