'use strict' module.exports = function (PromiseArgument) { var Promise; function throat(size, fn) { var queue = [] function run(fn, self, args) { if (size) { size-- var result = new Promise(function (resolve) { resolve(fn.apply(self, args)) }) result.then(release, release) return result } else { return new Promise(function (resolve) { queue.push(new Delayed(resolve, fn, self, args)) }) } } function release() { size++ if (queue.length) { var next = queue.shift() next.resolve(run(next.fn, next.self, next.args)) } } if (typeof size === 'function') { var temp = fn; fn = size; size = temp; } if (typeof size !== 'number') { throw new TypeError( 'Expected throat size to be a number but got ' + typeof size ); } if (fn !== undefined && typeof fn !== 'function') { throw new TypeError( 'Expected throat fn to be a function but got ' + typeof fn ); } if (typeof fn === 'function') { return function () { var args = []; for (var i = 0; i < arguments.length; i++) { args.push(arguments[i]); } return run(fn, this, args); } } else { return function (fn) { if (typeof fn !== 'function') { throw new TypeError( 'Expected throat fn to be a function but got ' + typeof fn ); } var args = []; for (var i = 1; i < arguments.length; i++) { args.push(arguments[i]); } return run(fn, this, args); } } } if (arguments.length === 1 && typeof PromiseArgument === 'function') { Promise = PromiseArgument; return throat; } else { Promise = module.exports.Promise; if (typeof Promise !== 'function') { throw new Error( 'You must provide a Promise polyfill for this library to work in older environments' ); } return throat(arguments[0], arguments[1]); } } /* istanbul ignore next */ if (typeof Promise === 'function') { module.exports.Promise = Promise; } function Delayed(resolve, fn, self, args) { this.resolve = resolve this.fn = fn this.self = self || null this.args = args }