insync
Version:
Higher-order functions and common patterns for asynchronous code. Node specific port of async.
611 lines (437 loc) • 13.6 kB
JavaScript
;
// Load modules
var Util = require('./util');
// Declare internals
var internals = {};
internals.doParallelLimit = function (limit, fn) {
return function () {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return fn.apply(null, [internals._eachLimit(limit)].concat(args));
};
};
internals._map = function (arr) {
var result = [];
for (var i = 0, il = arr.length; i < il; ++i) {
result.push({
index: i,
value: arr[i]
});
}
return result;
};
internals._unmap = function (arr) {
var result = [];
for (var i = 0, il = arr.length; i < il; ++i) {
result.push(arr[i].value);
}
return result;
};
internals._asyncMap = function (eachfn, arr, iterator, callback) {
arr = internals._map(arr);
if (typeof callback !== 'function') {
eachfn(arr, function (item, callback) {
iterator(item.value, function (err) {
callback(err);
});
});
} else {
(function () {
var results = [];
eachfn(arr, function (item, callback) {
iterator(item.value, function (err, value) {
results[item.index] = value;
callback(err);
});
}, function (err) {
callback(err, results);
});
})();
}
};
internals._filter = function (eachfn, arr, iterator, callback) {
var results = [];
arr = internals._map(arr);
eachfn(arr, function (item, callback) {
iterator(item.value, function (err, value) {
if (err) {
return callback(err);
} else if (value) {
results.push(item);
}
callback();
});
}, function (err) {
if (err) {
return callback(err);
}
results.sort(function (a, b) {
return a.index - b.index;
});
results = internals._unmap(results);
callback(null, results);
});
};
internals._reject = function (eachfn, arr, iterator, callback) {
var results = [];
arr = internals._map(arr);
eachfn(arr, function (item, callback) {
iterator(item.value, function (err, value) {
if (err) {
return callback(err);
} else if (!value) {
results.push(item);
}
callback();
});
}, function (err) {
if (err) {
return callback(err);
}
results.sort(function (a, b) {
return a.index - b.index;
});
results = internals._unmap(results);
callback(null, results);
});
};
internals._detect = function (eachfn, arr, iterator, callback) {
eachfn(arr, function (item, cb) {
iterator(item, function (err, result) {
if (err) {
callback(err);
callback = Util.noop;
} else if (result) {
callback(null, item);
callback = Util.noop;
} else {
cb();
}
});
}, callback);
};
internals._concat = function (eachfn, arr, fn, callback) {
var r = [];
eachfn(arr, function (x, cb) {
fn(x, function (err, y) {
r = r.concat(y || []);
cb(err);
});
}, function (err) {
callback(err, r);
});
};
// Used in flow.js
module.exports.doSeries = internals.doSeries = function (fn) {
return function () {
for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
return fn.apply(null, [module.exports.eachSeries].concat(args));
};
};
// Used in flow.js
module.exports.doParallel = internals.doParallel = function (fn) {
return function () {
for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
args[_key3] = arguments[_key3];
}
return fn.apply(null, [module.exports.each].concat(args));
};
};
// Used in flow.js
module.exports._eachLimit = internals._eachLimit = function (limit) {
return function (arr, iterator, callback) {
callback = callback || Util.noop;
if (!arr.length || limit <= 0) {
return callback();
}
var completed = 0;
var started = 0;
var running = 0;
var errored = false;
(function replenish() {
var iteratorCallback = function iteratorCallback(err) {
if (err) {
callback(err);
callback = Util.noop;
errored = true;
} else {
completed++;
running--;
if (completed >= arr.length) {
callback();
} else {
replenish();
}
}
};
while (running < limit && started < arr.length && errored === false) {
started++;
running++;
iterator(arr[started - 1], iteratorCallback);
}
})();
};
};
internals._eachOfLimit = function (limit) {
return function (object, iterator, callback) {
callback = callback || Util.noop;
var isArrayLike = Util.isArrayLike(object);
var size = undefined;
var keys = undefined;
if (isArrayLike) {
size = object.length;
} else {
keys = Object.keys(object);
size = keys.length;
}
if (!size || limit <= 0) {
return callback();
}
var completed = 0;
var started = 0;
var running = 0;
var errored = false;
(function replenish() {
var iteratorCallback = function iteratorCallback(err) {
if (err) {
callback(err);
callback = Util.noop;
errored = true;
} else {
completed++;
running--;
if (completed >= size) {
callback();
} else {
replenish();
}
}
};
while (running < limit && started < size && errored === false) {
var key = isArrayLike ? started : keys[started];
started++;
running++;
iterator(object[key], key, iteratorCallback);
}
})();
};
};
// Used in flow.js
module.exports._mapLimit = internals._mapLimit = function (limit) {
return internals.doParallelLimit(limit, internals._asyncMap);
};
module.exports.each = function (arr, iterator, callback) {
callback = callback || Util.noop;
if (!arr.length) {
return callback();
}
var completed = 0;
var done = function done(err) {
if (err) {
callback(err);
callback = Util.noop;
} else {
++completed;
if (completed >= arr.length) {
callback();
}
}
};
for (var i = 0, il = arr.length; i < il; ++i) {
iterator(arr[i], Util.onlyOnce(done));
}
};
module.exports.eachSeries = function (arr, iterator, callback) {
callback = callback || Util.noop;
if (!arr.length) {
return callback();
}
var completed = 0;
var iterate = function iterate() {
iterator(arr[completed], function (err) {
if (err) {
callback(err);
callback = Util.noop;
} else {
completed++;
if (completed >= arr.length) {
callback();
} else {
iterate();
}
}
});
};
iterate();
};
module.exports.eachLimit = function (arr, limit, iterator, callback) {
var fn = internals._eachLimit(limit);
fn.apply(null, [arr, iterator, callback]);
};
module.exports.eachOf = function (object, iterator, callback) {
var isArrayLike = Util.isArrayLike(object);
var size = undefined;
var keys = undefined;
if (isArrayLike) {
size = object.length;
} else {
keys = Object.keys(object);
size = keys.length;
}
callback = callback || Util.noop;
if (!size) {
return callback();
}
var completed = 0;
var done = function done(err) {
if (err) {
callback(err);
callback = Util.noop;
} else {
++completed;
if (completed >= size) {
callback();
}
}
};
if (isArrayLike) {
for (var i = 0; i < size; ++i) {
iterator(object[i], i, Util.onlyOnce(done));
}
} else {
for (var i = 0; i < size; ++i) {
var key = keys[i];
iterator(object[key], key, Util.onlyOnce(done));
}
}
};
module.exports.eachOfSeries = function (object, iterator, callback) {
var isArrayLike = Util.isArrayLike(object);
var size = undefined;
var keys = undefined;
if (isArrayLike) {
size = object.length;
} else {
keys = Object.keys(object);
size = keys.length;
}
callback = callback || Util.noop;
if (!size) {
return callback();
}
var completed = 0;
var complete = function complete(err) {
if (err) {
callback(err);
callback = Util.noop;
} else {
completed++;
if (completed >= size) {
callback();
} else {
iterate();
}
}
};
var iterate = isArrayLike ? function () {
iterator(object[completed], completed, complete);
} : function () {
var key = keys[completed];iterator(object[key], key, complete);
};
iterate();
};
module.exports.eachOfLimit = function (arr, limit, iterator, callback) {
var fn = internals._eachOfLimit(limit);
fn.apply(null, [arr, iterator, callback]);
};
module.exports.map = internals.doParallel(internals._asyncMap);
module.exports.mapSeries = internals.doSeries(internals._asyncMap);
module.exports.mapLimit = function (arr, limit, iterator, callback) {
return internals._mapLimit(limit)(arr, iterator, callback);
};
module.exports.filter = internals.doParallel(internals._filter);
module.exports.filterSeries = internals.doSeries(internals._filter);
module.exports.reject = internals.doParallel(internals._reject);
module.exports.rejectSeries = internals.doSeries(internals._reject);
// reduce() only has a series version.
// A parallel reduce() won't work in many situations.
module.exports.reduce = function (arr, memo, iterator, callback) {
module.exports.eachSeries(arr, function (item, callback) {
iterator(memo, item, function (err, value) {
memo = value;
callback(err);
});
}, function (err) {
callback(err, memo);
});
};
module.exports.reduceRight = function (arr, memo, iterator, callback) {
var reversed = [];
for (var i = arr.length - 1; i >= 0; --i) {
reversed.push(arr[i]);
}
module.exports.reduce(reversed, memo, iterator, callback);
};
module.exports.detect = internals.doParallel(internals._detect);
module.exports.detectSeries = internals.doSeries(internals._detect);
module.exports.sortBy = function (arr, iterator, callback) {
module.exports.map(arr, function (item, callback) {
iterator(item, function (err, criteria) {
if (err) {
return callback(err);
}
callback(null, {
value: item,
criteria: criteria
});
});
}, function (err, results) {
if (err) {
return callback(err);
}
results.sort(function (left, right) {
var a = left.criteria;
var b = right.criteria;
return a < b ? -1 : a > b ? 1 : 0;
});
results = internals._unmap(results);
callback(null, results);
});
};
module.exports.some = function (arr, iterator, callback) {
module.exports.each(arr, function (item, cb) {
iterator(item, function (err, value) {
if (err) {
callback(err);
callback = Util.noop;
} else if (value) {
callback(null, true);
callback = Util.noop;
}
cb();
});
}, function (err) {
callback(err, false);
});
};
module.exports.every = function (arr, iterator, callback) {
module.exports.each(arr, function (item, cb) {
iterator(item, function (err, value) {
if (err) {
callback(err);
callback = Util.noop;
} else if (!value) {
callback(null, false);
callback = Util.noop;
}
cb();
});
}, function (err) {
callback(err, true);
});
};
module.exports.concat = internals.doParallel(internals._concat);
module.exports.concatSeries = internals.doSeries(internals._concat);