首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >node.js中的异步for循环

node.js中的异步for循环
EN

Stack Overflow用户
提问于 2014-01-17 19:03:49
回答 3查看 107K关注 0票数 33

我是个新手,我对这个node.js有点困惑,我的应用程序在一个callback..In循环中,我正在调用一个异步函数调用,我想我的问题是,在我得到异步调用的响应之前,我的for循环被循环了。

我的代码:

代码语言:javascript
复制
async.forEach(Object.keys(config), function(key, next) {
        search(config[key].query, function(err, result) { // 
        console.log("fffffffffff="+ util.inspect(result))-------- >>>Getting undefined..
            if (err) return next(err) // 
            var json = JSON.stringify({
                "result": result
            });
            results[key] = {
                "result": result
            }
            console.log("rrrrrrrr="+util.inspect(results[key]))
            next() // <---- critical piece.  This is how the forEach knows to continue to the next loop.  Must be called inside search's callback so that it doesn't loop prematurely.                   
        })
    },
    function(err) {
        console.log('iterating done');

         res.writeHead(200, {
        'content-type': 'application/json'
    });
    res.end(JSON.stringify(results));  
    });


}

搜索功能代码:

代码语言:javascript
复制
var matches = [];
    var qrySubString = query.substring(0, 4);
    client.query("select * from xxxxxxxxx where level4 ILIKE '%" + query + "%'", function(err, row1, fields) {
        for (var id in row1.rows) {                
            var match, name;                
            if (query == row1.rows[id].level4) {
                match = true;
                name = row1.rows[id].level4;
            }
            else {
                match = false;
                name = query;
            }
            matches.push({
                "id": id,
                "name": row1.rows[id].level4,
                "score": 100,
                "match": match,
                "type": [{
                    "id": "/people/presidents",
                    "name": "US President"
                }]
            })
        }           
        callback(matches);
    })

我想在成功执行1个搜索函数后执行for循环,我想我必须使用async for loop.Please指导我提前解决this..Thanks ..

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-01-17 19:41:34

我已经将您的代码示例减少到以下几行,以便更容易理解该概念的解释。

代码语言:javascript
复制
var results = [];
var config = JSON.parse(queries);
for (var key in config) {
    var query = config[key].query;
    search(query, function(result) {
        results.push(result);
    });
}
res.writeHead( ... );
res.end(results);

前面代码的问题是search函数是异步的,因此当循环结束时,没有任何回调函数被调用。因此,results列表为空。

要解决这个问题,您必须将代码放在回调函数中的循环之后。

代码语言:javascript
复制
    search(query, function(result) {
        results.push(result);
        // Put res.writeHead( ... ) and res.end(results) here
    });

然而,由于回调函数被多次调用(每次迭代调用一次),您需要以某种方式知道所有回调函数都已被调用。为此,您需要计算回调的数量,并检查该数量是否等于异步函数调用的数量。

要获取所有密钥的列表,请使用Object.keys。然后,为了遍历这个列表,我使用了.forEach (您也可以使用for (var i = 0, key = keys[i]; i < keys.length; ++i) { .. },但这可能会产生问题,请参阅JavaScript closure inside loops – simple practical example)。

下面是一个完整的示例:

代码语言:javascript
复制
var results = [];
var config = JSON.parse(queries);
var onComplete = function() {
    res.writeHead( ... );
    res.end(results);
};
var keys = Object.keys(config);
var tasksToGo = keys.length;
if (tasksToGo === 0) {
   onComplete();
} else {
    // There is at least one element, so the callback will be called.
    keys.forEach(function(key) {
        var query = config[key].query;
        search(query, function(result) {
            results.push(result);
            if (--tasksToGo === 0) {
                // No tasks left, good to go
                onComplete();
            }
        });
    });
}

注意:上例中的异步代码是并行执行的。如果需要以特定的顺序调用函数,则可以使用递归来获得所需的效果:

代码语言:javascript
复制
var results = [];
var config = JSON.parse(queries);
var keys = Object.keys(config);
(function next(index) {
    if (index === keys.length) { // No items left
        res.writeHead( ... );
        res.end(results);
        return;
    }
    var key = keys[index];
    var query = config[key].query;
    search(query, function(result) {
        results.push(result);
        next(index + 1);
    });
})(0);

我所展示的是概念,您可以在您的实现中使用许多(第三方) NodeJS模块中的一个,例如async

票数 77
EN

Stack Overflow用户

发布于 2014-01-17 19:34:52

您已经正确地诊断出了您的问题,所以做得很好。一旦你调用你的搜索代码,for循环就会继续运行。

我是https://github.com/caolan/async的铁杆粉丝,它对我很有帮助。基本上,你会得到类似这样的结果:

代码语言:javascript
复制
var async = require('async')
async.eachSeries(Object.keys(config), function (key, next){ 
  search(config[key].query, function(err, result) { // <----- I added an err here
    if (err) return next(err)  // <---- don't keep going if there was an error

    var json = JSON.stringify({
      "result": result
    });
    results[key] = {
      "result": result
    }
    next()    /* <---- critical piece.  This is how the forEach knows to continue to
                       the next loop.  Must be called inside search's callback so that
                       it doesn't loop prematurely.*/
  })
}, function(err) {
  console.log('iterating done');
}); 

我希望这对你有帮助!

票数 31
EN

Stack Overflow用户

发布于 2014-01-17 20:18:24

我喜欢在这个场景中使用递归模式。例如,如下所示:

代码语言:javascript
复制
// If config is an array of queries
var config = JSON.parse(queries.queryArray);   

// Array of results
var results;

processQueries(config);

function processQueries(queries) {
    var searchQuery;

    if (queries.length == 0) {
        // All queries complete
        res.writeHead(200, {'content-type': 'application/json'});
        res.end(JSON.stringify({results: results}));
        return;
    }

    searchQuery = queries.pop();

    search(searchQuery, function(result) {
        results.push(JSON.stringify({result: result}); 
        processQueries();            
    });
}

processQueries是一个递归函数,它将从查询数组中提取一个查询元素进行处理。然后,当查询完成时,回调函数再次调用processQueries。当没有剩余的查询时,processQueries知道结束。

使用数组来实现这一点是最简单的,但我想它也可以修改为使用对象键/值。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21184340

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档