'use strict'; (function() { function asyncMap(forEach, collection, iterator, that, callback) { var type = Ox.typeOf(collection), results = type == 'object' ? {} : []; callback = Ox.last(arguments); that = arguments.length == 5 ? that : null; forEach(collection, function(value, key, collection, callback) { iterator(value, key, collection, function(value) { results[key] = value; callback(); }); }, that, function() { callback(type == 'string' ? results.join('') : results); }); }; Ox.asyncMap = function(array, iterator, that, callback) { array = Ox.makeArray(array); callback = Ox.last(arguments); that = arguments.length == 4 ? that : null; if (array.some(Ox.isArray)) { Ox.serialMap(array, function(value, key, array, callback) { Ox.parallelMap(Ox.makeArray(value), iterator, callback); }, callback); } else { Ox.parallelMap(array, iterator, callback); } }; /*@ Ox.nonblockingForEach Non-blocking forEach with synchronous iterator (col, iterator[, that], callback[, ms]) -> undefined @*/ Ox.nonblockingForEach = function(collection, iterator, that, callback, ms) { var i = 0, keys, last = Ox.last(arguments), n, time, type = Ox.typeOf(collection); callback = Ox.isFunction(last) ? last : arguments[arguments.length - 2]; collection = type == 'array' || type == 'object' ? collection : Ox.toArray(collection); keys = type == 'object' ? Object.keys(collection) : Ox.range(collection.length); ms = ms || 1000; n = Ox.len(collection); that = arguments.length == 5 || ( arguments.length == 4 && Ox.isFunction(last) ) ? that : null; time = +new Date(); iterate(); function iterate() { Ox.forEach(keys.slice(i), function(key) { if (key in collection) { try { iterator.call(that, collection[key], key, collection); } catch(error) { if (error === Ox.BreakError) { i = n; } throw e; } } i++; +new Date() >= time + ms && Ox.Break(); }); if (i < n) { setTimeout(function() { time = +new Date(); iterate(); }, 1); } else { callback(); } } }; /*@ Ox.nonblockingMap Non-blocking map with synchronous iterator (collection, iterator[, that]) -> undefined collection Collection iterator Iterator function that The iterator's this binding callback Callback function @*/ Ox.nonblockingMap = function(collection, iterator, that, callback, ms) { var last = Ox.last(arguments), type = Ox.typeOf(collection), results = type == 'object' ? {} : []; callback = Ox.isFunction(last) ? last : arguments[arguments.length - 2]; that = arguments.length == 5 || ( arguments.length == 4 && Ox.isFunction(last) ) ? that : null; Ox.nonblockingForEach(collection, function(value, key, collection) { results[key] = iterator.call(that, value, key, collection); }, function() { callback(type == 'string' ? results.join('') : results); }, ms); }; /*@ Ox.parallelForEach forEach with asynchronous iterator, running in parallel (collection, iterator[, that], callback) -> undefined collection Collection iterator Iterator function value <*> Value key Key collection The collection callback Callback function that The iterator's this binding callback Callback function @*/ Ox.parallelForEach = function(collection, iterator, that, callback) { var i = 0, n, type = Ox.typeOf(collection); callback = Ox.last(arguments); collection = type == 'array' || type == 'object' ? collection : Ox.toArray(collection); n = Ox.len(collection); that = arguments.length == 4 ? that : null; Ox.forEach(collection, function(value, key, collection) { iterator.call(that, value, key, collection, function() { ++i == n && callback(); }); }); }; /*@ Ox.parallelMap Parallel map with asynchronous iterator (collection, iterator[, that], callback) -> undefined collection Collection iterator Iterator function value <*> Value key Key collection The collection callback Callback function that The iterator's this binding callback Callback function results Results @*/ Ox.parallelMap = function() { asyncMap.apply(null, [Ox.parallelForEach].concat(Ox.toArray(arguments))); }; /*@ Ox.serialForEach forEach with asynchronous iterator, run serially (collection, iterator[, that], callback) -> undefined collection Collection iterator Iterator function value <*> Value key Key collection The collection callback Callback function that The iterator's this binding callback Callback function @*/ Ox.serialForEach = function(collection, iterator, that, callback) { var i = 0, keys, n, type = Ox.typeOf(collection); callback = Ox.last(arguments); collection = type == 'array' || type == 'object' ? collection : Ox.toArray(collection); keys = type == 'object' ? Object.keys(collection) : Ox.range(collection.length); n = Ox.len(collection); that = arguments.length == 4 ? that : null; iterate(); function iterate() { keys[i] in collection && iterator.call( that, collection[keys[i]], keys[i], collection, function() { ++i < n ? iterate() : callback(); } ); } }; /*@ Ox.serialMap Serial map with asynchronous iterator (collection, iterator[, that], callback) -> undefined collection Collection iterator Iterator function value <*> Value key Key collection The collection callback Callback function that The iterator's this binding callback Callback function results Results @*/ Ox.serialMap = function(collection, iterator, that, callback) { asyncMap.apply(null, [Ox.serialForEach].concat(Ox.toArray(arguments))); }; }());