Node.js和Express:如何在异步操作后返回响应

22

我刚接触Node.js,所以还在学习异步函数和回调函数。我现在的问题是如何在异步操作中读取文件后返回响应。

我的理解是发送响应的方式如下(这对我有效):

app.get('/search', function (req, res) {
    res.send("request received");
});

然而,我现在想要读取一个文件,在数据上执行一些操作,然后将结果作为响应返回。如果我想要在数据上执行的操作很简单,我可以像这样做 - 在行内执行它们,并保持对res对象的访问,因为它仍然在范围内。

app.get('/search', function (req, res) {
    fs.readFile("data.txt", function(err, data) {
        result = process(data.toString());
        res.send(result);
    });
});

然而,我需要执行的文件操作非常冗长和复杂,以至于我将它们分离到了另一个单独的文件中的自己的函数中。因此,我的代码看起来更像是这样的:

 app.get('/search', function (req, res) {
    searcher.do_search(res.query);
    // ??? Now what ???
});

为了发送结果,我需要调用res.send。但是,在上面的函数中无法直接调用它,因为do_search是异步完成的。而在回调到do_search时无法调用它,因为res对象不在作用域内。

请问有人能帮助我理解在Node.js中处理这个问题的正确方法吗?


我会建议,要么将 res 对象作为参数传递到函数中,要么使其可以传递一个函数作为参数,然后在工作完成时调用它(即创建自己的回调函数)。后者可能更好,因为它不会将您的代码与 Express 的 API 耦合。 - Joe Clay
2个回答

19

如果没有共享作用域,想要在不同的函数之间访问一个变量,可以将其作为参数传递。

您可以只传递res,然后在函数内部访问querysend两个变量。


出于关注点分离的目的,最好传递一个回调函数。

这样,do_search只需要知道如何执行查询并运行函数即可。这使其更加通用(因此可重用)。

searcher.do_search(res.query, function (data) {
    res.send(...);
});

function do_search(query, callback) {
    callback(...);
} 

3
传递回调函数绝对是正确的方法。赞同建议。 - Lars de Bruijn
感谢您的帮助。我最终修改了我的do_search函数以接受回调,并且它运行得很好。 - ekl
这个回答解决了问题吗?为什么示例中没有包括涉及的函数app.get - Brent Bradburn
@nobar — 是的。因为直接复制问题中的一大堆代码没有意义,这只会使发现差异变得更加困难。 - Quentin

4

现有的回答是完全有效的,您也可以使用ES2017引入的async/await关键字。可以使用下面的函数:

app.get('/search', async(req, res, next) {
  try {
    const answer = await searcher.do_search(req.query);
    res.send(answer);
  }
  catch(error) {
    return next(error);
  }
});

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