2015-05-09 51 views
1

所以我很难过,并且似乎无法掌握发生了什么。我有一个需要一系列命令的函数。对nodejs中的收集项目运行查询

var collection = [{ordernumber: 1, href: 'FileDetails.aspx?FileId=1234'}, 
        {ordernumber: 2, href: 'FileDetails.aspx?FileId=1478'}]; 
var OrdersListToImport = []; 

function loopOrders(collection, callback) { 
    for(var i = 0; i < collection.length; i++) { 
    console.log('processing order #: ' + collection[i].ordernumber); 
    var answersReturned = 0; 
    db.needsImported(collection[i].ordernumber, function(answer) { 
     if (answer) { 
     OrdersListToImport.push(collection[i]); 
     //console.log(collection[i]); 
     } 
     if (++answersReturned == collection.length) { 
     callback(); 
     } 

    }); 
    } 

} 

NeedsImported功能如下:

needsImported: function(ordernumber, callback) { 
    pool.query('Select controlnumber From orders Where ordernumber = ?', [ordernumber], function(err, result) { 
     if (!err) { 
     if (result.length == 0) { 
      callback(true); 
     } 
     else { 
      callback(false); 
     } 
     } 
    }); 
    } 

当db.needsImported的回调函数内,集合[I]变为不确定。这让我很生气,所以我做了一个小样本文件,看看是否有一个原因,我无法从回调函数中访问参数。它按预期工作,只推偶数。这里是示例:

var nums = []; 
var collection = [1,2,3,4,5,6,7,8,9,10]; 

displayValue(collection, function() { 

}); 
console.log(nums); 

function displayValue(col, callback) { 
    for(var i = 0; i < col.length; i++) { 
    sleep(col[i] * 500, function() { 
     console.log('Count: ' + col[i]); 
     if (col[i] % 2 == 0) { 
     nums.push(col[i]); 
     } 
    }); 
    callback(); 
    } 
} 

function sleep(time, callback) { 
    var stop = new Date().getTime(); 
    while(new Date().getTime() < stop + time) { 
     ; 
    } 
    callback(); 
} 

我希望有人能帮助我了解我做错了什么。

回答

0

如果您希望collection[i]不是未定义的console.log(i),您可能会更清楚地看到问题所在。

您的for循环中发生了什么是您遍历数组并发射多个异步任务。当循环完成时,i的值为2. i是一个可以访问您的回调的封​​闭变量,但请记住异步时间在这里,您的needsImported回调函数全部在之后被调用您的for循环已完成,所以很自然地,collection[2]未定义。为了解决这个问题,你可以只摆脱指数和使用Array.forEach来代替:

function loopOrders(collection, callback) { 
    var answersReturned = 0; 
    collection.forEach(function(item, index) { 
     needsImported(item.ordernumber, function(answer) { 
      console.log('index:', index); 
      if (answer) { 
       OrdersListToImport.push(item); 
      } 
      if (++answersReturned == collection.length) { 
       callback(); 
      } 
     }); 
    }); 
} 

还要注意的是,如果你确实需要跟踪指数的回调,您可以收到它作为第二个参数的forEach回调,因为我已经完成上述。

还要说明一点:)有这个代码显著的缺陷:

needsImported: function(ordernumber, callback) { 
    pool.query('Select controlnumber From orders Where ordernumber = ?', [ordernumber], function(err, result) { 
     if (!err) { 
     if (result.length == 0) { 
      callback(true); 
     } 
     else { 
      callback(false); 
     } 
     } 
    }); 
    } 

如果err确实发生,你忽略它,但更糟的是,你不调用回调。令人困惑的错误将从此出现。在节点中通常的做法是将err var作为回调的第一个参数,所以在成功的情况下,您可以这样做callback(null, true)

+0

这解决了这个问题。所以,我原本以为如果它的速度太快,我可能会得到2的回调,但我现在实际上在i = 5。我认为使用forEach会搞砸了,因为它检查一个项目,但它现在是下一个项目,所以我可能最终将不正确的项目推入数组中。你能告诉我为什么一个forEach物品不会推动不正确的物品,如果它会推错不正确的“我”?或者指出我的方向,以便我可以了解它? – ScottieDont

+0

你的回调不是“进行得太快”以至于不能完成你的循环。您误解了节点事件循环的工作原理以及您的代码在单个线程上执行的事实。您的for循环会在调用任何回调之前确定性地完成迭代。把它想象成一个事件队列。您的for循环正在发生,因为它是由事件A触发的。在执行过程中,它将两个未决事件B和C推送到此队列中。事件A的代码路径必须完全完成才能完成,否则B或C将弹出堆栈。 –

+0

我不确定你的意思是什么forEach推动不正确的项目。 –