2

我是 Node.js 和异步编码的新手。我需要编写与 Node.js 一起使用的嵌套 for 循环的等价物。我知道我的问题与此处发布的问题非常相似:nested loops asynchronusly in nodejs, next loop must start only after one getting completed,但即使在详细查看该帖子之后,我也无法修复我的代码。

我正在使用 XML 提要。“解析器”使用 xml2js 包。如果我删除 sql 查询(为此我正在使用 mysql 节点包),循环将完全按预期运行,但是当我放入 sql 查询时,所有订单都会首先得到处理,输出“DONE”,然后查询失败,因为它试图重复查找最后一个订单的项目。

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

任何有关如何以更符合节点习惯的方式重新编码的帮助或建议将不胜感激。

非常感谢!六个霍比特人

    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
4

3 回答 3

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必须在其所有异步处理完成后调用其回调参数。在这种情况下,您有两个级别,这使得您很难在脑海中跟踪,但这是相同的概念。

于 2012-12-10T17:34:32.650 回答
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
于 2012-12-10T17:35:57.317 回答
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);
                }
            }
        );
于 2014-06-22T14:42:13.233 回答