68 lines
		
	
	
		
			1.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			68 lines
		
	
	
		
			1.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict';
 | |
| module.exports = (iterable, mapper, opts) => new Promise((resolve, reject) => {
 | |
| 	opts = Object.assign({
 | |
| 		concurrency: Infinity
 | |
| 	}, opts);
 | |
| 
 | |
| 	if (typeof mapper !== 'function') {
 | |
| 		throw new TypeError('Mapper function is required');
 | |
| 	}
 | |
| 
 | |
| 	const concurrency = opts.concurrency;
 | |
| 
 | |
| 	if (!(typeof concurrency === 'number' && concurrency >= 1)) {
 | |
| 		throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${concurrency}\` (${typeof concurrency})`);
 | |
| 	}
 | |
| 
 | |
| 	const ret = [];
 | |
| 	const iterator = iterable[Symbol.iterator]();
 | |
| 	let isRejected = false;
 | |
| 	let iterableDone = false;
 | |
| 	let resolvingCount = 0;
 | |
| 	let currentIdx = 0;
 | |
| 
 | |
| 	const next = () => {
 | |
| 		if (isRejected) {
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		const nextItem = iterator.next();
 | |
| 		const i = currentIdx;
 | |
| 		currentIdx++;
 | |
| 
 | |
| 		if (nextItem.done) {
 | |
| 			iterableDone = true;
 | |
| 
 | |
| 			if (resolvingCount === 0) {
 | |
| 				resolve(ret);
 | |
| 			}
 | |
| 
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		resolvingCount++;
 | |
| 
 | |
| 		Promise.resolve(nextItem.value)
 | |
| 			.then(el => mapper(el, i))
 | |
| 			.then(
 | |
| 				val => {
 | |
| 					ret[i] = val;
 | |
| 					resolvingCount--;
 | |
| 					next();
 | |
| 				},
 | |
| 				err => {
 | |
| 					isRejected = true;
 | |
| 					reject(err);
 | |
| 				}
 | |
| 			);
 | |
| 	};
 | |
| 
 | |
| 	for (let i = 0; i < concurrency; i++) {
 | |
| 		next();
 | |
| 
 | |
| 		if (iterableDone) {
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| });
 |