2017-07-30 10 views
0

私はサードパーティのサービスからアイテムを内部に持っているインベントリを要求し、特定の基準に基づいてそれらをフィルタリングするスクリプトを作成しています。 Filterモジュールは正しい応答を返送しますが、フィルターを呼び出すメソッドは、テストに合格した項目を配列に追加できません。コールバック前にNodeJSが待機する

具体的には、Inventory.loadClean()はサードパーティのAPIからデータを取得してから、項目をループして条件を満たしているかどうかを確認するInventory.filterを呼び出します。項目がそれをするならば、配列にそれを加えます。

filter: function (inv, rules, cb) { 
    var filtered_items = []; 
    for(var i = 0; i < inv.length; i++) { 
     Filter.itemPasses(inv[i], rules, function(passes, stage) { 
      //console.log(passes, stage); 
      if(passes) { 
       filtered_items.push(inv[i]); 
      } 
      if(i + 1 == inv.length) { 
       console.log("i+1:", i+1, "inv:", inv.length); 
       cb(filtered_items); 
      } 
     }); 
    } 
} 

Inventory.filter

メソッドの呼び出し

// This is how Intentory.filter is called. All the parameters are correct. 
Inventory.filter(inv, rules, function(filtered) { 
    console.log(filtered); 
    next(filtered); 
}); 

それはかなりまっすぐ進むのです。 Filter.itemPassesがアイテムを評価し、コールバックで値がpassesであるかどうかは、アイテムがチェックを通過するかどうかに基づいて真または偽です。

ザ・表現i + 1 == inv.lengthを評価文がここに発見された場合:Underscore _.each callback when finished?

とアイデアが最後の要素が処理されるときにコールバックを呼び出すことです。それが動作することは非常に論理的なようですが、そうではありません。私はまだ空の配列を取得しています。

私はFilterのすべてのメソッドをチェックしており、正しく評価していることに注意してください。場合によっては、filter.jsがリンクになっています。https://gist.github.com/meletisf/d32a241ba2cbb168527f4342eabdf2a6

私はそれが非同期の問題であることは間違いないと確信していますが、原因はわかりません。

+0

'Filter.meetsPriceLimits'は' Cache.get() 'を呼び出しています。この関数が非同期で応答することは可能でしょうか? 'resp'パラメータを持つコールバックは、その疑いを引き起こす可能性があります。 – ccprog

+0

はい。 'Cache.get()'私はRedisの非同期ラッパーです。私はこれが問題を引き起こしていることを知っていましたが、複数のコールバックを使用することによって、スクリプトはitentedとして機能します。とにかく、私はそれを固定した方法について私の答えをチェックしてください。 – Meletis

答えて

0

おそらく競合の問題です。これは、コールバックのためのより良い条件である、とも閉鎖私かもしれません:各変数iは、以下の結論につまずい動作したかを検査しようとした後

filter: function (inv, rules, cb) { 
var filtered_items = []; 
var count=0; 
for(let i = 0; i < inv.length; i++) {//the let is important 
    Filter.itemPasses(inv[i], rules, function(passes, stage) { 
     //console.log(passes, stage); 
     if(passes) { 
      filtered_items.push(inv[i]); 
     } 
     count++; 
     if(count == inv.length) {//the improved condition 
      console.log("i+1:", i+1, "inv:", inv.length); 
      cb(filtered_items); 
     } 
    }); 
    } 
} 
+0

興味深い。これで18個の未定義要素の配列が返されます。 18は、テストに合格した項目の数です。 – Meletis

+0

@Meletisあなたが使用する必要があります。 –

0

forループからの変数iは、ループ内で異常な挙動を示しました。もっと具体的には、それは常に31だった。なぜこれが起こっていたのかわからないが、私はinv[i]から現在の項目を取得する必要があることがわかった。代わりに、Filter.itemPassesを変更してアイテムオブジェクトがすべての条件を満たす場合はそれを返すようにします。私はまた、ジョナスが提案したコードを追加しました。私はなぜそれが動作するかわからないが、それは動作します。それがなければ配列は常に空です。

残念ながら私はなぜコードがうんざりしていたのか正確な答えはわかりませんが、以下に述べた修正プログラムを実装することで、私はうまく動作します。

+0

ループ外の関数スコープで 'var i'を定義しています。コールバックは非同期で呼び出されるので、呼び出された時点でループは既に終了しており、 'i'はその最終値に達しています。 – ccprog

+1

ループのための* closures内部を見てください - 簡単な実用的な例*ここではSO –

関連する問題