1 2/* 3usage: 4 5// do something to a list of things 6asyncMap(myListOfStuff, function (thing, cb) { doSomething(thing.foo, cb) }, cb) 7// do more than one thing to each item 8asyncMap(list, fooFn, barFn, cb) 9 10*/ 11 12module.exports = asyncMap 13 14function asyncMap () { 15 var steps = Array.prototype.slice.call(arguments) 16 , list = steps.shift() || [] 17 , cb_ = steps.pop() 18 if (typeof cb_ !== "function") throw new Error( 19 "No callback provided to asyncMap") 20 if (!list) return cb_(null, []) 21 if (!Array.isArray(list)) list = [list] 22 var n = steps.length 23 , data = [] // 2d array 24 , errState = null 25 , l = list.length 26 , a = l * n 27 if (!a) return cb_(null, []) 28 function cb (er) { 29 if (er && !errState) errState = er 30 31 var argLen = arguments.length 32 for (var i = 1; i < argLen; i ++) if (arguments[i] !== undefined) { 33 data[i - 1] = (data[i - 1] || []).concat(arguments[i]) 34 } 35 // see if any new things have been added. 36 if (list.length > l) { 37 var newList = list.slice(l) 38 a += (list.length - l) * n 39 l = list.length 40 process.nextTick(function () { 41 newList.forEach(function (ar) { 42 steps.forEach(function (fn) { fn(ar, cb) }) 43 }) 44 }) 45 } 46 47 if (--a === 0) cb_.apply(null, [errState].concat(data)) 48 } 49 // expect the supplied cb function to be called 50 // "n" times for each thing in the array. 51 list.forEach(function (ar) { 52 steps.forEach(function (fn) { fn(ar, cb) }) 53 }) 54} 55