You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					82 lines
				
				1.5 KiB
			
		
		
			
		
	
	
					82 lines
				
				1.5 KiB
			| 
								 
											4 years ago
										 
									 | 
							
								'use strict';
							 | 
						||
| 
								 | 
							
								const AggregateError = require('aggregate-error');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = async (
							 | 
						||
| 
								 | 
							
									iterable,
							 | 
						||
| 
								 | 
							
									mapper,
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										concurrency = Infinity,
							 | 
						||
| 
								 | 
							
										stopOnError = true
							 | 
						||
| 
								 | 
							
									} = {}
							 | 
						||
| 
								 | 
							
								) => {
							 | 
						||
| 
								 | 
							
									return new Promise((resolve, reject) => {
							 | 
						||
| 
								 | 
							
										if (typeof mapper !== 'function') {
							 | 
						||
| 
								 | 
							
											throw new TypeError('Mapper function is required');
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										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 errors = [];
							 | 
						||
| 
								 | 
							
										const iterator = iterable[Symbol.iterator]();
							 | 
						||
| 
								 | 
							
										let isRejected = false;
							 | 
						||
| 
								 | 
							
										let isIterableDone = false;
							 | 
						||
| 
								 | 
							
										let resolvingCount = 0;
							 | 
						||
| 
								 | 
							
										let currentIndex = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const next = () => {
							 | 
						||
| 
								 | 
							
											if (isRejected) {
							 | 
						||
| 
								 | 
							
												return;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const nextItem = iterator.next();
							 | 
						||
| 
								 | 
							
											const i = currentIndex;
							 | 
						||
| 
								 | 
							
											currentIndex++;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if (nextItem.done) {
							 | 
						||
| 
								 | 
							
												isIterableDone = true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if (resolvingCount === 0) {
							 | 
						||
| 
								 | 
							
													if (!stopOnError && errors.length !== 0) {
							 | 
						||
| 
								 | 
							
														reject(new AggregateError(errors));
							 | 
						||
| 
								 | 
							
													} else {
							 | 
						||
| 
								 | 
							
														resolve(ret);
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												return;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											resolvingCount++;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											(async () => {
							 | 
						||
| 
								 | 
							
												try {
							 | 
						||
| 
								 | 
							
													const element = await nextItem.value;
							 | 
						||
| 
								 | 
							
													ret[i] = await mapper(element, i);
							 | 
						||
| 
								 | 
							
													resolvingCount--;
							 | 
						||
| 
								 | 
							
													next();
							 | 
						||
| 
								 | 
							
												} catch (error) {
							 | 
						||
| 
								 | 
							
													if (stopOnError) {
							 | 
						||
| 
								 | 
							
														isRejected = true;
							 | 
						||
| 
								 | 
							
														reject(error);
							 | 
						||
| 
								 | 
							
													} else {
							 | 
						||
| 
								 | 
							
														errors.push(error);
							 | 
						||
| 
								 | 
							
														resolvingCount--;
							 | 
						||
| 
								 | 
							
														next();
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											})();
							 | 
						||
| 
								 | 
							
										};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for (let i = 0; i < concurrency; i++) {
							 | 
						||
| 
								 | 
							
											next();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if (isIterableDone) {
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									});
							 | 
						||
| 
								 | 
							
								};
							 |