117 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			117 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict';
 | |
| 
 | |
| module.exports = function (PromiseArgument) {
 | |
|   var Promise;
 | |
|   function throat(size, fn) {
 | |
|     var queue = new 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.isEmpty()) {
 | |
|         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;
 | |
| }
 | |
| 
 | |
| function Queue() {
 | |
|   this._s1 = [];
 | |
|   this._s2 = [];
 | |
| }
 | |
| 
 | |
| Queue.prototype.push = function (value) {
 | |
|   this._s1.push(value);
 | |
| };
 | |
| 
 | |
| Queue.prototype.shift = function () {
 | |
|   var s2 = this._s2;
 | |
|   if (s2.length === 0) {
 | |
|     var s1 = this._s1;
 | |
|     if (s1.length === 0) {
 | |
|       return;
 | |
|     }
 | |
|     this._s1 = s2;
 | |
|     s2 = this._s2 = s1.reverse();
 | |
|   }
 | |
|   return s2.pop();
 | |
| };
 | |
| 
 | |
| Queue.prototype.isEmpty = function () {
 | |
|   return !this._s1.length && !this._s2.length;
 | |
| };
 |