(function(global) { 'use strict'; if (typeof module === 'object' && module.exports) module.exports = new ExecProto(); else global.exec = new ExecProto(); function ExecProto() { var slice = Array.prototype.slice, /** * function do save exec of function * @param callback * @param arg1 * ... * @param argN */ exec = function(callback) { var ret, isFunc = typeof callback === 'function', args = slice.call(arguments, 1); if (isFunc) ret = callback.apply(null, args); return ret; }; /* * return function that calls callback with arguments */ exec.with = function(callback) { var slice = Array.prototype.slice, args = slice.call(arguments, 1); return function() { var array = slice.call(arguments), all = args.concat(array); return callback.apply(null, all); }; }; /** * return save exec function * @param callback */ exec.ret = function() { var result, args = slice.call(arguments); args.unshift(exec); result = exec.with.apply(null, args); return result; }; /** * function do conditional save exec of function * @param condition * @param callback * @param func */ exec.if = function(condition, callback, func) { var ret; if (condition) exec(callback); else exec(func, callback); return ret; }; /** * exec function if it exist in object * * @param obj * @param name * @param arg */ exec.ifExist = function(obj, name, arg) { var ret, func = obj && obj[name]; if (func) func = func.apply(obj, arg); return ret; }; exec.parallel = function(funcs, callback) { var ERROR = 'could not be empty!', keys = [], callbackWas = false, arr = [], obj = {}, count = 0, countFuncs = 0, type = getType(funcs); if (!funcs) throw Error('funcs' + ERROR); if (!callback) throw Error('callback' + ERROR); switch(type) { case 'array': countFuncs = funcs.length; funcs.forEach(function(func, num) { exec(func, function() { checkFunc(num, arguments); }); }); break; case 'object': keys = Object.keys(funcs); countFuncs = keys.length; keys.forEach(function(name) { var func = funcs[name]; exec(func, function() { checkFunc(name, arguments, obj); }); }); break; } function checkFunc(num, data) { var args = slice.call(data, 1), isLast = false, error = data[0], length = args.length; ++count; isLast = count === countFuncs; if (!error) if (length >= 2) arr[num] = args; else arr[num] = args[0]; if (!callbackWas && (error || isLast)) { callbackWas = true; if (type === 'array') callback.apply(null, [error].concat(arr)); else callback(error, arr); } } }; /** * load functions thrue callbacks one-by-one * @param funcs {Array} - array of functions */ exec.series = function(funcs, callback) { var fn, i = funcs.length, check = function(error) { var done; --i; if (!i || error) { done = true; exec(callback, error); } return done; }; if (!Array.isArray(funcs)) throw Error('funcs should be array!'); fn = funcs.shift(); exec(fn, function(error) { if (!check(error)) exec.series(funcs, callback); }); }; exec.each = function(array, iterator, callback) { var listeners = array.map(function(item) { return iterator.bind(null, item); }); if (!listeners.length) callback(); else exec.parallel(listeners, callback); }; exec.eachSeries = function(array, iterator, callback) { var listeners = array.map(function(item) { return iterator.bind(null, item); }); if (typeof callback !== 'function') throw Error('callback should be function'); if (!listeners.length) callback(); else exec.series(listeners, callback); }; /** * function execute param function in * try...catch block * * @param callback */ exec.try = function(callback) { var ret; try { ret = callback(); } catch(error) { ret = error; } return ret; }; function getType(variable) { var regExp = new RegExp('\\s([a-zA-Z]+)'), str = {}.toString.call(variable), typeBig = str.match(regExp)[1], result = typeBig.toLowerCase(); return result; } return exec; } })(this);