2015-05-09 28 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推動不正確的項目。 –