fa
Version:
fluent async: functional programming support for asynchronous functions.
254 lines (249 loc) • 7.5 kB
JavaScript
(function() {
var fa;
fa = function(concurrency, do_all, with_index) {
var api, nullFn, tmpl;
if (concurrency == null) concurrency = Number.MAX_VALUE;
if (do_all == null) do_all = false;
if (with_index == null) with_index = false;
if (typeof process === "undefined" || process === null) process = {};
if (process.nextTick == null) {
process.nextTick = function(cb) {
return cb();
};
}
api = {};
api.reduce = function(arr, memo, iterator, callback) {
var count, errs, isArray, keys, nextItem, pending, size, theCallback;
isArray = Array.isArray(arr);
try {
keys = isArray ? arr : Object.keys(arr);
} catch (e) {
return callback(new Error("Trying to reduce over non iterable"));
}
if (!keys.length) return callback(void 0, memo);
if (do_all) errs = [];
size = pending = keys.length;
count = 0;
theCallback = function(err, result) {
if (err) {
if (errs) {
errs.push(err);
} else {
callback(err);
callback = function() {};
return;
}
} else {
}
if (--pending === 0) {
err = errs && errs.length ? errs : void 0;
return callback(err, result);
}
return process.nextTick(function() {
return nextItem(result);
});
};
nextItem = function(memo) {
var key, val;
if (isArray) {
val = arr[count++];
return iterator(memo, val, theCallback);
} else {
key = keys[count++];
val = arr[key];
return iterator(memo, val, key, theCallback);
}
};
return nextItem(memo);
};
nullFn = function() {
return;
};
tmpl = function(name, initResults, single_argument_callback, handleResult, handleReturn) {
return function(arr, iterator, callback, what) {
var count, errs, finished, i, isArray, keys, nextItem, pending, results, size, theCallback, workers, _ref, _results;
if (what == null) what = 0;
isArray = Array.isArray(arr);
keys = isArray ? arr : Object.keys(arr);
results = initResults();
if (!keys.length) {
if (single_argument_callback) {
return callback(results);
} else {
return callback(void 0, results);
}
}
if (do_all) errs = [];
workers = 0;
size = pending = keys.length;
count = 0;
finished = false;
theCallback = function(val, index) {
return function(err, result) {
workers -= 1;
if (single_argument_callback) {
result = err;
err = null;
}
if (err) {
if (errs) {
errs.push(err);
} else {
callback(err);
callback = function() {};
return;
}
} else {
results = handleResult(results, result, val, index, callback);
if (results === true) {
callback = function() {};
finished = true;
return;
}
}
if (--pending === 0) {
err = errs && errs.length ? errs : void 0;
if (handleReturn) {
return handleReturn(err, callback, results, size);
} else {
return callback(err, results);
}
}
return process.nextTick(function() {
return nextItem();
});
};
};
nextItem = function() {
var index, key, val;
if (workers++ < concurrency && count < size && !finished) {
index = count++;
if (isArray) {
val = arr[index];
if (with_index) {
return iterator(val, index, theCallback(val, index));
} else {
return iterator(val, theCallback(val, index));
}
} else {
key = keys[index];
val = arr[key];
if (with_index) {
return iterator(val, key, index, theCallback(val, index));
} else {
return iterator(val, key, theCallback(val, index));
}
}
}
};
_results = [];
for (i = 1, _ref = (concurrency < pending ? concurrency : pending); 1 <= _ref ? i <= _ref : i >= _ref; 1 <= _ref ? i++ : i--) {
_results.push(nextItem());
}
return _results;
};
};
api.each = tmpl('each', nullFn, false, nullFn);
api.map = tmpl('map', (function() {
return [];
}), false, function(results, result, val, index) {
results[index] = result;
return results;
});
api.concat = tmpl('concat', (function() {
return [];
}), false, function(results, result) {
if (Array.isArray(result)) {
return results.concat(result);
} else {
return results;
}
});
api.filter = tmpl('filter', (function() {
return [];
}), true, function(results, result, val) {
if (result) results.push(val);
return results;
});
api.reject = tmpl('reject', (function() {
return [];
}), true, function(results, result, val) {
if (!result) results.push(val);
return results;
});
api.detect = tmpl('detect', (function() {
return;
}), true, function(results, result, val, index, callback) {
if (results === void 0) results = 0;
if (result) {
callback(val, results);
return true;
}
return ++results;
});
api.any = tmpl('any', (function() {
return false;
}), true, (function(results, result, val, index, callback) {
if (result) {
callback(true);
return true;
}
}), function(err, callback) {
return callback(false);
});
api.all = tmpl('all', (function() {
return true;
}), true, (function(results, result, val, index, callback) {
if (results === true) results = 0;
if (result) {
return ++results;
} else {
return results;
}
}), function(err, callback, results, size) {
return callback(results === size);
});
api.queue = function(concurrency) {
return fa(concurrency, do_all, with_index);
};
api.series = function() {
return fa(1, do_all, with_index);
};
api.with_index = function() {
return fa(concurrency, do_all, true);
};
api["continue"] = function() {
return fa(concurrency, true, with_index);
};
api.forEach = api.each;
api.select = api.filter;
api.find = api.detect;
api.inject = api.reduce;
api.foldl = api.reduce;
api.some = api.any;
api.every = api.all;
api.concurrent = api.queue;
api.c = api.queue;
api["if"] = function(conditional, trueFn, elseFn, callback) {
if (!callback) {
callback = elseFn;
elseFn = null;
}
if (conditional) {
return trueFn(callback);
} else {
if (elseFn) {
return elseFn(callback);
} else {
return callback();
}
}
};
return api;
};
if (typeof module !== 'undefined') {
module.exports = fa();
} else {
window.fa = fa();
}
}).call(this);