iterate.js (1794B)
1 var async = require('./async.js') 2 , abort = require('./abort.js') 3 ; 4 5 // API 6 module.exports = iterate; 7 8 /** 9 * Iterates over each job object 10 * 11 * @param {array|object} list - array or object (named list) to iterate over 12 * @param {function} iterator - iterator to run 13 * @param {object} state - current job status 14 * @param {function} callback - invoked when all elements processed 15 */ 16 function iterate(list, iterator, state, callback) 17 { 18 // store current index 19 var key = state['keyedList'] ? state['keyedList'][state.index] : state.index; 20 21 state.jobs[key] = runJob(iterator, key, list[key], function(error, output) 22 { 23 // don't repeat yourself 24 // skip secondary callbacks 25 if (!(key in state.jobs)) 26 { 27 return; 28 } 29 30 // clean up jobs 31 delete state.jobs[key]; 32 33 if (error) 34 { 35 // don't process rest of the results 36 // stop still active jobs 37 // and reset the list 38 abort(state); 39 } 40 else 41 { 42 state.results[key] = output; 43 } 44 45 // return salvaged results 46 callback(error, state.results); 47 }); 48 } 49 50 /** 51 * Runs iterator over provided job element 52 * 53 * @param {function} iterator - iterator to invoke 54 * @param {string|number} key - key/index of the element in the list of jobs 55 * @param {mixed} item - job description 56 * @param {function} callback - invoked after iterator is done with the job 57 * @returns {function|mixed} - job abort function or something else 58 */ 59 function runJob(iterator, key, item, callback) 60 { 61 var aborter; 62 63 // allow shortcut if iterator expects only two arguments 64 if (iterator.length == 2) 65 { 66 aborter = iterator(item, async(callback)); 67 } 68 // otherwise go with full three arguments 69 else 70 { 71 aborter = iterator(item, key, async(callback)); 72 } 73 74 return aborter; 75 }