2013-09-05 22 views
0

我有一個循環執行數據庫調用(sqlite3)以減少回調中的庫存。它工作得很好,減少了「部分使用」的數量爲1.使用原型將屬性添加到函數會導致函數參數變得不明確

平均可以有1到60個數組元素,所以這個循環會快速連續創建1到60個異步任務。回調函數簽名是由JS綁定到sqlite3確定的(錯誤,行)。我無法改變它。

 i = 0; 
    while (i < struct.PortionsUsed.length) { 
     portionUsed = struct.PortionsUsed[i]; 
     Db.get("SELECT blah blah WHERE portion = ? ORDER BY date LIMIT 1", portionUsed, selectCallBack); 
     i++; 
    } 

陣列containes大量重複的元素和的排序陣列將,當然,把它們都彼此相鄰,使得更多的邏輯可以創建的「portionUsed」項的數量的計數中扣除從一次通話的庫存中,將60個任務減少到10個左右,所以它值得去做。這意味着回調必須進行計數,但沒有通用的機制來提供它。

關閉不起作用(嘗試它),因爲回調觸發時,計數是循環中最後一個計數的值。我需要在回調任務創建時提供當前的「計數」,以便在回調內部可用,所以我試圖對回調函數對象使用原型擴展,以便通過指定新函數沿每個函數的唯一「計數」拖動每個Db調用實例化的回調函數。

 struct.PortionsUsed = struct.PortionsUsed.sort(); // Get all identical portion items adjacent to each other. 
    i = 0; 
    while (i < struct.PortionsUsed.length) { 
     // i points at the first portion item, whatever it is. 
     j = i + 1; 
     while (j < struct.PortionsUsed.length && struct.PortionsUsed[i] === struct.PortionsUsed[j]) { 
      ++j; 
     } 
     // j points at 1 past the last identical portion item. 
     count = j - i; // count has the number of portions to deduct from inventory. 

     // Get the oldest Portion row and reduce the qty by the count. 
     portionUsed = struct.PortionsUsed[i]; 
     if (debug) {console.log('Starting Select for ' + portionUsed + ' - count=' + count);} 
     selectCallBack.prototype.count = count; 
     selectCallBack.prototype.portionUsed = portionUsed; 
     Db.get("SELECT rowid AS rowNum, portion, qty FROM Portion WHERE portion = ? ORDER BY date LIMIT 1", portionUsed, new selectCallBack); 
     //Db.get("SELECT rowid AS rowNum, portion, qty FROM Portion WHERE portion = ? ORDER BY date LIMIT 1", portionUsed, 
     // function(error, row) {count; portionUsed; selectCallBack(error, row);}); 
     i = j; 
    } 

回調現在根本不會工作,因爲(錯誤,行)都是未定義的。爲什麼?我怎樣才能解決這個問題?在回調中,this.count可用,就像我想要的一樣。

有沒有更好的方法來解決這個問題?

這裏的回調:

 function selectCallBack(error, row) { 
     var count = this.count;    // made active ONLY when attempting to use prototype 
     var portionUsed = this.portionUsed; // made active ONLY when attempting to use prototype 
     var portion; 

     if (debug) {console.log('Hit selectCallBack. count=' + count + ' portionUsed=' + portionUsed);} 
     if (debug) {console.log(typeof error + typeof row);} 
     if (error !== null) { 
      if (debug) {console.log('selectCallBack error:\n' + error);} 
      success = false; 
     } else { 
      // real work goes here 
     } 
    }  // no return statement of any kind. 

閉合輸出:

Starting Select for Coffee - count=5 
    Starting Select for Hot Tea - count=2 
    Hit selectCallBack. count=2 portionUsed=Hot Tea 
    objectobject 
    Hit selectCallBack. count=2 portionUsed=Hot Tea 
    objectobject 

原型辦法輸出:

Starting Select for Coffee - count=5 
    Hit selectCallBack. count=5 portionUsed=Coffee 
    undefinedundefined 
    selectCallBack error: 
    undefined 
    Starting Select for Hot Tea - count=2 
    Hit selectCallBack. count=2 portionUsed=Hot Tea 
    undefinedundefined 
    selectCallBack error: 
    undefined 
+0

*「關閉將不起作用(嘗試它),因爲回調觸發時,計數是循環中最後一個計數的值。」* ...然後你做錯了。 – user2736012

+1

在循環中修改'selectCallBack.prototype.count'時,從'new selectCallBack()'創建的所有對象都將看到更新。換句話說,'.prototype'對象在所有實例之間共享,因此它們都會觀察更新。爲什麼不直接將屬性直接放在您創建的對象上? – user2736012

+0

...如果'DB.get()'的第三個參數應該是回調函數,那麼當您執行'new selectCallback'時,您不會傳遞一個參數,除非在調用它時從'selectCallback'返回一個參數。 – user2736012

回答

0

您關閉試圖從事實遭受的唯一方法來創建JavaScript中的新變量作用域是調用一個函數。當您在循環中創建函數時,所有函數都將在相同的變量範圍內創建。

爲了彌補這一點,您需要在循環的每次迭代中調用一個函數,傳遞需要在該新變量範圍內保留的值,並在同一範圍內創建回調函數。這樣,循環中創建的每個函數都將在唯一的函數範圍內創建。

IMO做這件事最清晰的方法是將需要作用域的代碼移動到一個新函數中,並在循環中調用它。

struct.PortionsUsed = struct.PortionsUsed.sort(); 
i = 0; 
while (i < struct.PortionsUsed.length) { 
    j = i + 1; 
    while (j < struct.PortionsUsed.length && struct.PortionsUsed[i] === struct.PortionsUsed[j]) { 
     ++j; 
    } 
    count = j - i; 
    portionUsed = struct.PortionsUsed[i]; 
    if (debug) {console.log('Starting Select for ' + portionUsed + ' - count=' + count);} 

    setHandler(Db, count, portionUsed, selectCallback); 

    i = j; 
} 

function setHandler(Db, count, portionUsed, callback) { 
    // In here, any of the above parameters can be used within the 
    // handler function created below. 
    Db.get("SELECT rowid AS rowNum, portion, qty FROM Portion WHERE portion = ? ORDER BY date LIMIT 1", 
      portionUsed, 
      function(error, row) { 
       console.log(count, portionUsed); // Not sure how you wanted to use these 
       callback(error, row); 
      } 
    ); 
} 

類似的解決方案是隻建立在我們的新功能的處理器,以及具備的功能返回。

struct.PortionsUsed = struct.PortionsUsed.sort(); 
i = 0; 
while (i < struct.PortionsUsed.length) { 
    j = i + 1; 
    while (j < struct.PortionsUsed.length && struct.PortionsUsed[i] === struct.PortionsUsed[j]) { 
     ++j; 
    } 
    count = j - i; 
    portionUsed = struct.PortionsUsed[i]; 
    if (debug) {console.log('Starting Select for ' + portionUsed + ' - count=' + count);} 

    Db.get("SELECT rowid AS rowNum, portion, qty FROM Portion WHERE portion = ? ORDER BY date LIMIT 1", 
      portionUsed, 
      setHandler(count, portionUsed, selectCallback) 
    ); 

    i = j; 
} 

function setHandler(count, portionUsed, callback) { 
    // In here, any of the above parameters can be used within the 
    // handler function that we create and return below. 
    return function(error, row) { 
     console.log(count, portionUsed); // Not sure how you wanted to use these 
     callback(error, row); 
    }; 
} 

有些人喜歡用內聯直接在循環做到這一點,立即調用的函數,但我認爲這雜波的代碼太多。我更喜歡使用命名函數。

+0

只要我看到你使用函數的輸出來返回一個函數,你就立即將我設置在正確的路徑上。這就是我所錯過的。我從來沒有想到這一點。謝謝! –

相關問題