我对 Node.js 中递归异步请求的行为有疑问。
下面的函数旨在从 MongoDB 返回搜索结果。如果初始搜索结果为空,我会将文本拆分为单独的单词,然后尝试递归地获取每个单词的 fetchResult(...) ,并将 res 对象作为参数传递。
function fetchResult(text, res){
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect(mongoURL + "/search", function (err, db) {
if(err) throw err;
db.collection('results', function(err, collection) {
// search for match that "begins with" text
collection.findOne({'text':new RegExp('^' + text, 'i')}, function(err, items){
var result = (items == null || items.result == null) ? "" : items;
if (result){
res.send(result);
}
else {
// no result, so fire off individual word queries - if any spaces found
if (text.indexOf(' ') > -1){
// split string into array
var textArray = text.split(" ");
// recursively process individual words
for (index = 0; index < textArray.length; index++) {
// ***** RACE CONDITION HERE? *****
fetchResult(textArray[index], res);
}
}
else {
// just return empty result
res.send(result);
}
}
});
});
});
}
我怀疑这可能会导致一些竞争条件,因为对 res 的引用异步扇出,并且当我运行代码并观察到以下错误时证实了这一点:
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:344:11)
所以我的问题是:如何实现按顺序执行单个字符串查询的所需递归行为,仅在找到第一个结果时返回(或在搜索根本没有返回结果时在过程结束时返回)?
最佳答案
您的代码需要一些重构。
首先,从 fetchResult
函数中删除 MongoClient.connect
调用。您可以连接一次并存储 db
对象以供以后使用。
其次,通过您的方法,您将为查询中的每个单词返回响应。我不认为递归调用是这里的方法。
如果您的第一个查询失败,您将有多个异步查询,并且您需要以某种方式聚合结果......这就是它变得棘手的地方。我对 Mongo 不太熟悉,但我相信您可以通过使用 find $in
检索一组结果来避免这种情况。请参阅this question ,也许有帮助。
关于javascript - Node.js 中的异步递归问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42903781/