Skip to content

Instantly share code, notes, and snippets.

@peatiscoding
Created May 19, 2016 16:48
Show Gist options
  • Save peatiscoding/8e802267ac8ae01ed0933dffa5a3979a to your computer and use it in GitHub Desktop.
Save peatiscoding/8e802267ac8ae01ed0933dffa5a3979a to your computer and use it in GitHub Desktop.
JavaScript looping asynchronous calls such as AJAX.
var BATCH = function(options) {
var args = options.args, // arguments for method without callback
method = options.method, // method to be invoked
done = options.done,
each = options.each;
// validate options
if ( ! args || ! Array.isArray(args)) {
throw 'args is required and must be array';
}
if ( ! method || typeof method != 'function') {
throw 'method is required and must be function';
}
var queue = args.slice(),
_results = [],
_lp = function(args) {
// Last argument is shifted.
if (args == undefined) {
// dispatch results
done && done(_results);
return;
}
// make sure all arguments is provided in array format. (so that we can apply them).
if ( ! Array.isArray(args)) {
args = [args];
}
// Append callback as a last call
args.push(function() {
// append results, if each is present call it.
if (each) {
var a = each.apply(null, arguments);
_results.push(a);
if (a == undefined) {
console && console.log && console.log('Warning "each" callback returns nothing.');
}
} else {
_results.push({
arguments: args,
result: arguments
});
}
// shift next set of argument.
_lp(queue.shift());
});
// Invoke
method.apply(null, args);
};
// kick off
_lp(queue.shift());
};
@llun
Copy link

llun commented May 20, 2016

More fancy version with generator and promise 😃

function chain(method, data) {
  function* promise(method, data) {
    let head;
    do {
      head = data.shift();
      if (head) yield () => new Promise(method.bind(this, ...head));
    } while(head);
  }

  let iterator = promise(method, data);
  let loop = iterator => {
    let next = iterator.next().value;
    if (next) next().then(() => loop(iterator));
  }
  loop(iterator);
}

and more simpler and compact version

function chain(method, data) {
  let items = data.map(item => () => new Promise(method.bind(this, ...item)));
  let loop = items => {
    let next = items.shift();
    if (next) next().then(() => loop(items));
  }
  loop(items);
}
chain((phase1, phase2, resolve) => {
  setTimeout(() => { console.log(`${phase1} ${phase2} output`); resolve() }, 1000);
}, [
  ['hello', 'print_me'],
  ['this', 'is'],
  ['simple', 'message'],
]);

@llun
Copy link

llun commented May 20, 2016

but actually, do you need the order? otherwise can use Promise.all for batching task.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment