2015-09-03 11 views
11

lodash forEachメソッドをmongoデータベースを呼び出すネストされた関数で使用しようとしています。Lodash:_.forEach with function

var jobs = []; 
_.forEach(ids, function(id) { 
    JobRequest.findByJobId(id, function(err, result) { 
     if(err) callback(err); 
     jobs.push(result); 
    }); 
}); 

callback(null, jobs); 

forEachとコールバックが内部関数が呼び出される前に実行されるため、問題があります。どうすれば解決できますか?

for eachおよびinner関数が完了した後でコールバックを呼び出すようにします。

+0

'async.map 'を使用してください。 – SLaks

答えて

8

JobRequest.findByJobIdは非同期操作です。 JavaScriptで非同期操作をブロックすることはできませんので、手動でカウントすることで同期する必要があります。例(簡略化のために省略エラー処理):

var results = []; 
var pendingJobCount = ids.length; 

_.forEach(ids, function(id) { 
    JobRequest.findByJobId(id, function(err, result) { 
     results.push(result); 
     if (--pendingJobCount === 0) callback(null, results); 
    }); 
}); 

ありますが、もちろん、ラッパーはこのようなものを行うために構築し、私はそれが実際にどのように動作するかを説明することを好みます。 promisesと呼ばれるラッパーの詳細については、dfsq's answerを参照してください。

また、非同期操作が順不同で完了することがあります。配列resultsの順序は、配列idsの順序と必ずしも一致しません。あなたは情報が接続されていることを必要とする場合は、代わりに、配列のマップで結果を収集することによって、例えば、それを自分で追跡する必要があります:

var results = {}; 
var pendingJobCount = ids.length; 

_.forEach(ids, function(id) { 
    JobRequest.findByJobId(id, function(err, result) { 
     results[id] = result; 
     if (--pendingJobCount === 0) callback(null, results); 
    }); 
}); 

この例では、あなたのids配列内の重複しないことを前提としています。重複キーの結果は無効になります。

エラー処理は、結果に追加情報を挿入することによって同様に機能します。別の例:あなたは、潜在的に処理する必要があること、

var promises = ids.map(function(id) { 
    return new Promise(function(resolve, reject) { 
     JobRequest.findByJobId(id, function (err, result) { 
      if (err) reject(err); 
      resolve(result); 
     }); 
    }); 
}); 

Promise.all(promises).then(function(jobs) { 
    callback(null, jobs); 
}, callback); 

// or shorter: Promise.all(promises).then(callback.bind(null, null), callback); 

注:

results.push({id: id, error: null, value: result}); 
11

もう一つのアプローチは、ジョブの結果が正しい順序で配列にプッシュされます。この場合には、約束にすべてをラップすることです状況がJobRequest.findByJobId要求が失敗した場合、約束をもって非常に簡単です:callbackをエラーコールバックとしてPromise.allに渡すだけです。

+1

現代のJavaScriptエンジン(または良いpolyfill)を使用すると、これはもっと読みやすい方法の1つです。 – jwueller