重新编码嵌套for循环以在node.js中使用async

时间:2012-12-10 17:21:17

标签: node.js asynchronous

我是Node.js和Async编码的新手。我需要编写一个嵌套for循环的等价物,它将与Node一起使用。我了解到我的问题与此处发布的问题非常相似:nested loops asynchronusly in nodejs, next loop must start only after one gets completed,但即使仔细查看该帖子,我也无法修复我的代码。

我正在使用XML Feed。 '解析器'使用xml2js包。该 如果我删除sql查询(我正在使用mysql节点包),循环运行完全如预期的那样,但是当我输入sql查询时,所有订单首先被处理,输出“DONE”,并且然后查询失败,因为它试图重复查找最后一个订单的项目。

我尝试用async.forEach循环替换for循环,但这没有帮助。

有关如何以更加惯用于节点的方式重新编码的任何帮助或建议将非常感激。

非常感谢! Sixhobbits

    parser.parseString(data, function (err, result) {
    if(err) throw(err);     
    var numOrders = result['Root']['Orders'][0]['Order'].length;
    var curr, currItem, currOrdId, items, sellersCode;
    console.log("Logging IDs of", numOrders, "orders");
    // for each order
    for (var j=0; j<numOrders; j++){
        //current order
        curr = result['Root']['Orders'][0]['Order'][j];         
        currOrdId = curr['OrderId'][0]          
        items = curr['Items'][0]['Item'];
        console.log("Order ID:", currOrdId, "--",items.length, "Items");
        // for each item
        for (var k=0; k<items.length; k++){
            currItem = items[k];
            sellersCode = currItem['SellersProductCode'][0];
            var sqlQuery = 'select data_index, fulltext_id, cataloginventory_stock_item.product_id from catalogsearch_fulltext inner join cataloginventory_stock_item where catalogsearch_fulltext.data_index like "' + sellersCode + '|%"' + 'and cataloginventory_stock_item.item_id = catalogsearch_fulltext.product_id';
            var query = connection.query(sqlQuery,function(err,rows,fields){
                if (err) throw(err);
                console.log("    Item ID          :",currItem['ItemId'][0]);
                console.log("    Full Text ID     :", rows[0]['fulltext_id']);
                console.log("    Product ID       :", rows[0]['product_id']);
            });
        }//for
    }//for
    console.log("DONE");
});//parseString

3 个答案:

答案 0 :(得分:4)

通过使用async.forEach,您走在正确的轨道上。以下是如何使用该代码重新编写代码:

parser.parseString(data, function (err, result) {
    if(err) throw(err);
    var numOrders = result['Root']['Orders'][0]['Order'].length;
    var currOrdId, items, sellersCode;
    console.log("Logging IDs of", numOrders, "orders");
    // for each order
    async.forEach(result['Root']['Orders'][0]['Order'], function (curr, callback1) {
        currOrdId = curr['OrderId'][0];
        items = curr['Items'][0]['Item'];
        console.log("Order ID:", currOrdId, "--",items.length, "Items");
        async.forEach(items, function (currItem, callback2) {
            sellersCode = currItem['SellersProductCode'][0];
            var sqlQuery = 'select data_index, fulltext_id, cataloginventory_stock_item.product_id from catalogsearch_fulltext inner join cataloginventory_stock_item where catalogsearch_fulltext.data_index like "' + sellersCode + '|%"' + 'and cataloginventory_stock_item.item_id = catalogsearch_fulltext.product_id';
            var query = connection.query(sqlQuery,function(err,rows,fields){
                console.log("    Item ID          :",currItem['ItemId'][0]);
                console.log("    Full Text ID     :", rows[0]['fulltext_id']);
                console.log("    Product ID       :", rows[0]['product_id']);
                callback2(err);
            });
        }, callback1);
    }, function (err) {
        console.log("DONE");
    });
});//parseString

async.forEach的每次迭代必须在其所有异步处理完成后调用其回调参数。在这种情况下,你有两个级别,这使得跟踪你的头脑更加困难,但它是相同的概念。

答案 1 :(得分:1)

这是一个经典的闭环问题。你需要通过传递currItem作为参数来打破闭包:

    for (var k=0; k<items.length; k++){
        currItem = items[k];
        sellersCode = currItem['SellersProductCode'][0];
        var sqlQuery = 'select data_index, fulltext_id, cataloginventory_stock_item.product_id from catalogsearch_fulltext inner join cataloginventory_stock_item where catalogsearch_fulltext.data_index like "' + sellersCode + '|%"' + 'and cataloginventory_stock_item.item_id = catalogsearch_fulltext.product_id';
        var query = connection.query(sqlQuery,(function(CI){
          return function(err,rows,fields){
            if (err) throw(err);
            console.log("    Item ID          :",CI['ItemId'][0]);
            console.log("    Full Text ID     :", rows[0]['fulltext_id']);
            console.log("    Product ID       :", rows[0]['product_id']);
          }
        })(currItem)); // Break closure by passing currItem as argument
    }//for

答案 2 :(得分:0)

我意识到这是一篇旧帖子,但你可能会觉得这个功能很有用

eachKVAsync = function(elements,userInfo,onKeyValue,ondone) {
    var onDone = ondone;
    var ret = null;
    var done=false;
    var isArray = typeof elements.forEach===$f$; 
    var keys   = isArray ? null     : [], 
        values = isArray ? elements : [];

    if (keys) {
        for (var k in elements) {
            keys.push(k);
            values.push(elements[k]);
        }
    }

    var aborted=false;
    var endLoop = function (userInfo){
        aborted=true;
        if (onDone) {
            onDone(userInfo,aborted);
            onDone = null;
        }
    }


    var i = 0;
    var iterate = function (userInfo) {
        if (i < values.length) {
            var ix=i;
            i++;
            onKeyValue((keys?keys[ix]:i),values[ix],userInfo,iterate,endLoop);          
        } else {
            if (onDone) {
                onDone(userInfo,aborted);
                onDone = null;
                return;
            }
        } 
    } 

    iterate(userInfo);

},

使用示例

        eachKVAsync(
            elements, {
                aValue: 2004
            },
            function onItem(key, value, info, nextItem, endLoop) {
                if (value.isOk) {
                    info.aValue += value.total;
                    setTimeout(nextItem,1000,info);
                } else {
                    endLoop(info);
                }
            },
            function afterLastItem(info, loopEndedEarly) {
                if (!loopEndedEarly) {
                    console.log(info.aValue);
                }
            }
        );