121 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			121 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
# Promise-parallel-throttle
 | 
						|
[](https://travis-ci.org/DJWassink/Promise-parallel-throttle)
 | 
						|
 | 
						|
Run a array of Promises in parallel. Kinda like Promise.all(), but throttled!
 | 
						|
 | 
						|
## Install 
 | 
						|
 | 
						|
### NPM
 | 
						|
```bash
 | 
						|
npm i promise-parallel-throttle -S
 | 
						|
```
 | 
						|
 | 
						|
### Yarn
 | 
						|
```bash
 | 
						|
yarn add promise-parallel-throttle
 | 
						|
```
 | 
						|
 | 
						|
## Usage
 | 
						|
 | 
						|
```js
 | 
						|
import Throttle from 'promise-parallel-throttle';
 | 
						|
 | 
						|
//Function which should return a Promise
 | 
						|
const doReq = async (firstName, lastName) => {
 | 
						|
    //Do something async.
 | 
						|
    return firstName + " " + lastName;
 | 
						|
}
 | 
						|
 | 
						|
const users = [
 | 
						|
    {firstName: "Irene", lastName: "Pullman"},
 | 
						|
    {firstName: "Sean",  lastName: "Parr"}
 | 
						|
];
 | 
						|
 | 
						|
//Queue with functions to be run
 | 
						|
const queue = users.map(user => () => doReq(user.firstName, user.lastName));
 | 
						|
 | 
						|
//Default Throttle runs with 5 promises parallel.
 | 
						|
const formattedNames = await Throttle.all(queue);
 | 
						|
 | 
						|
console.log(formattedNames); //['Irene Pullman', 'Sean Parr']
 | 
						|
```
 | 
						|
 | 
						|
## API
 | 
						|
### Throttle.all
 | 
						|
`Throttle.all(tasks, options)`
 | 
						|
 | 
						|
Throttle.all is made to behave exactly like Promise.all but instead of all the tasks running in parallel it runs a maxium amount of tasks in parallel.
 | 
						|
Only the tasks parameter is required while the [options](#options-object) parameter is optional.
 | 
						|
 | 
						|
### Throttle.sync
 | 
						|
`Throttle.sync(tasks, options)`
 | 
						|
 | 
						|
Throttle.sync runs all the tasks synchronously. 
 | 
						|
Once again the tasks array is required, the [options](#options-object) are optional. 
 | 
						|
Be aware that this method is simply a wrapper to pass `maxInProgress` with 1. So overwriting this option in the options object would run the tasks again in parallel.
 | 
						|
 | 
						|
### Throttle.raw
 | 
						|
`Throttle.raw(tasks, options)`
 | 
						|
 
 | 
						|
 The raw method instead of returning the tasks their results, will return a [result](#result-object--progress-callback) object. 
 | 
						|
 Useful if you wan't more statistics about the execution of your tasks. Once again the tasks are required while the [options](#options-object) are optional.
 | 
						|
 | 
						|
#### Option's Object
 | 
						|
|Parameter|Type|Default|Definition|
 | 
						|
|:---|:---|:---|:---|
 | 
						|
|maxInProgress |Integer|5| max amount of parallel threads|
 | 
						|
|failFast |Boolean|true (false for the [raw](#throttleraw) method)| reject after a single error, or keep running|
 | 
						|
|progressCallback |Function|Optional| callback with progress reports|
 | 
						|
|nextCheck |Function|Optional| function which should return a promise, if the promise resolved true the next task is spawn, errors will propagate and should be handled in the calling code|
 | 
						|
 | 
						|
#### Result object / Progress callback
 | 
						|
The `progressCallback` and the `Raw` will return a `Result` object with the following properties:
 | 
						|
 | 
						|
|Property|Type|Start value|Definition|
 | 
						|
|:---|:---|:---|:---|
 | 
						|
|amountDone|Integer|0|amount of tasks which are finished|
 | 
						|
|amountStarted|Integer|0|amount of tasks which started|
 | 
						|
|amountResolved|Integer|0|amount of tasks which successfully resolved|
 | 
						|
|amountRejected|Integer|0|amount of tasks which returned in an error and are aborted|
 | 
						|
|amountNextCheckFalsey|Integer|0|amount of tasks which got a falsey value in the [nextCheck](#nextcheck)|
 | 
						|
|rejectedIndexes|Array|[]|all the indexes in the tasks array where the promise rejected|
 | 
						|
|resolvedIndexes|Array|[]|all the indexes in the tasks array where the promise resolved|
 | 
						|
|nextCheckFalseyIndexes|Array|[]|all the indexes in the tasks array where the [nextCheck](#nextcheck) returned a falsey value|
 | 
						|
|taskResults|Array|[]|array containing the result of every task|
 | 
						|
 | 
						|
#### nextCheck
 | 
						|
All the `Throttle` methods have a `nextCheck` method which will be used to verify if a next task is allowed to start. 
 | 
						|
 | 
						|
The default `nextCheck` is defined like this;
 | 
						|
```js
 | 
						|
const defaultNextTaskCheck = (status, tasks) => {
 | 
						|
    return new Promise((resolve, reject) => {
 | 
						|
        resolve(status.amountStarted < tasks.length);
 | 
						|
    });
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
This function will get a status object as parameter which adheres to the [Result object](#result-object--progress-callback) and it also receives the list of tasks.
 | 
						|
In the default `nextCheck` we simply check if the amount of started exceeds the amount to be done, if not we are free to start an other task.
 | 
						|
 | 
						|
This function can be useful to write your own scheduler based on, for example ram/cpu usage.
 | 
						|
Lets say that your tasks use a lot of ram and you don't want to exceed a certain amount.
 | 
						|
You could then write logic inside a `nextCheck` function which resolves after there is enough ram available to start the next task.
 | 
						|
 | 
						|
If a custom implementation decides to reject, the error is propagated and should be handled in the user it's code. If a custom implementation returns a falsey value the task will simply not execute and the next task will be scheduled.
 | 
						|
 | 
						|
## Example
 | 
						|
Check out the example's directory, it's heavily documented so it should be easy to follow.
 | 
						|
 | 
						|
To run the example, at least Node 8.x.x is required, since it supports native async/await.
 | 
						|
 | 
						|
Simply run the example with npm:
 | 
						|
```
 | 
						|
npm run-script names
 | 
						|
```
 | 
						|
 | 
						|
Or with Yarn:
 | 
						|
```
 | 
						|
yarn names
 | 
						|
```
 |