| 
									
										
										
										
											2021-01-15 17:50:02 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @template T | 
					
						
							| 
									
										
										
										
											2021-04-12 15:17:43 +08:00
										 |  |  |  * @template {Error} E | 
					
						
							| 
									
										
										
										
											2021-01-15 17:50:02 +08:00
										 |  |  |  * @param {Iterable<T>} items initial items | 
					
						
							|  |  |  |  * @param {number} concurrency number of items running in parallel | 
					
						
							| 
									
										
										
										
											2025-03-12 09:56:14 +08:00
										 |  |  |  * @param {(item: T, push: (item: T) => void, callback: (err?: E) => void) => void} processor worker which pushes more items | 
					
						
							|  |  |  |  * @param {(err?: E) => void} callback all items processed | 
					
						
							| 
									
										
										
										
											2021-01-15 17:50:02 +08:00
										 |  |  |  * @returns {void} | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const processAsyncTree = (items, concurrency, processor, callback) => { | 
					
						
							|  |  |  | 	const queue = Array.from(items); | 
					
						
							|  |  |  | 	if (queue.length === 0) return callback(); | 
					
						
							|  |  |  | 	let processing = 0; | 
					
						
							|  |  |  | 	let finished = false; | 
					
						
							|  |  |  | 	let processScheduled = true; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-12 22:21:21 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {T} item item | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2021-01-15 17:50:02 +08:00
										 |  |  | 	const push = item => { | 
					
						
							|  |  |  | 		queue.push(item); | 
					
						
							|  |  |  | 		if (!processScheduled && processing < concurrency) { | 
					
						
							|  |  |  | 			processScheduled = true; | 
					
						
							|  |  |  | 			process.nextTick(processQueue); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-12 22:21:21 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {E | null | undefined} err error | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2021-01-15 17:50:02 +08:00
										 |  |  | 	const processorCallback = err => { | 
					
						
							|  |  |  | 		processing--; | 
					
						
							|  |  |  | 		if (err && !finished) { | 
					
						
							|  |  |  | 			finished = true; | 
					
						
							|  |  |  | 			callback(err); | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (!processScheduled) { | 
					
						
							|  |  |  | 			processScheduled = true; | 
					
						
							|  |  |  | 			process.nextTick(processQueue); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const processQueue = () => { | 
					
						
							|  |  |  | 		if (finished) return; | 
					
						
							|  |  |  | 		while (processing < concurrency && queue.length > 0) { | 
					
						
							|  |  |  | 			processing++; | 
					
						
							| 
									
										
										
										
											2023-06-12 22:21:21 +08:00
										 |  |  | 			const item = /** @type {T} */ (queue.pop()); | 
					
						
							| 
									
										
										
										
											2021-01-15 17:50:02 +08:00
										 |  |  | 			processor(item, push, processorCallback); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		processScheduled = false; | 
					
						
							|  |  |  | 		if (queue.length === 0 && processing === 0 && !finished) { | 
					
						
							|  |  |  | 			finished = true; | 
					
						
							|  |  |  | 			callback(); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	processQueue(); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports = processAsyncTree; |