Skip to content

Instantly share code, notes, and snippets.

@iammapping
Created January 7, 2015 06:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iammapping/9a870e13fda05c7ed25d to your computer and use it in GitHub Desktop.
Save iammapping/9a870e13fda05c7ed25d to your computer and use it in GitHub Desktop.
do iterator one by one in series
/**
* call iterate one by one
* @param {array|object} collection
* @param {function} iterate
* @param {function} cb the finished callback
*/
function oneByOne(collection, iterate, cb) {
var failed = false,
completed = 0, // record the count of completed iterate
len = 0,
keys = null,
maps = null; // store the result of each iterate
cb = cb || function() {};
// detect collection is an array or hash object
// init maps with the same type
if (Array.isArray(collection)) {
maps = [];
} else if (typeof collection === 'object') {
maps = {}
} else {
throw new TypeError('First argument must be an collection');
}
if (typeof iterate !== 'function') {
throw new TypeError('Second argument must be a function');
}
keys = Object.keys(collection);
len = keys.length;
if (!len) {
return cb();
}
(function next() {
if (failed) {
return;
}
var key = keys[completed];
iterate(collection[key], (function(fn) {
// make sure fn execute once
var called = false;
return function() {
if (called) {
throw new Error('Callback already called');
}
called = true;
fn.apply(this, arguments);
};
}(function() {
var args = Array.prototype.slice.call(arguments, 0),
err = args.shift();
// save the result of current iterate
maps[key] = args;
if (err) {
// iterate meet error
// stop other iterate
// call cb with error
failed = true;
maps = null;
return cb(err);
}
// increase the completed iterate
// move index to next item of collection
completed++;
if (completed < len) { // iterate is not finished
// start next iterate
next();
} else if (completed === len) { // iterate is finished
// the finish callback with more than one argument
// first argument always be error
// need the result maps of each iterate
if (cb.length > 1) {
// call cb with error(null) and maps
return cb(null, maps);
} else {
// just call cb with none argument
maps = null;
return cb();
}
}
})));
}());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment