npm package: @little-island/workers
Description: Stuff to help with workers
Author: Nikolas Karinja
Latest version: 0.1.8

# Workers

These are some classes that will help easily use and manage WebWorkers in the projects you are working on. It's loosely based on [SimonDev's Threading Technique](https://www.youtube.com/watch?v=a1L7k35EHIc) with JavaScript WebWorkers that he used for his procedural world generation.

## How it works

The most likely reason you would need to use many workers in projects is to complete complicated and performance-crippling tasks on different threads. I have created two classes that make doing this a walk in the park; ```WorkerThreadPool``` and ```WorkerThread```. 

#### WorkerThreadPool ```(options?: object)```

This class essentially manages all the workers you create within it. It allows to run as many workers as you want at once as long as it is less than or equal to the amount if threads on your CPU. If you run more workers than the ```maxUsableThreads``` you have allowed it to use, it will queue those workers to run as soon as there is an empty thread available for it (like when one of the previous workers finishes its task). This allows for very easy management without haing to hastle to much with the performance.

> - **constructor** ```(options? object)```
Sets the max amount of threads that this pool is allowed to use (default is your CPU thread count).
> - **add** ```(workerThread? WorkerThread): void```
Stores a worker in this pool under its UUID.
> - **enqueue** ```(workerThread? WorkerThread): void```
This adds the worker to the queue if all the threads are busy and if it hasn't already been placed inside the queue.
> - **createWorker** ```(fileName: string, options?: object): WorkerThread```
This creates and returns a new worker and stores it in this pool.
> - **isBusy** ```(workerThread: WorkerThread): boolean```
Checks if the worker is busy.
> - **isQueued** ```(workerThread: WorkerThread): boolean```
Checks if the worker is in the queue.
> - **checkMessage** ```(workerThread: WorkerThread): void```
This is called when a worker has completed its task. It removes the worker from the "busy" list and runs the next worker in the queue. If it isn't a permanent worker, it remove it this pool's storage and terminate it. 
> - **run** ```(workerThread: WorkerThread): void```
This decides if the worker should be executed and become "busy", or be put in the queue to be executed when a thread is available.
> - **test** ```(): void```
This creates a bunch of sample workers to test if this pool is queueing, executing, and terminating workers properly.

#### WorkerThread

This class contains the actual WebWorker. You can use tell it what data to send and what to when its task is complete. Unless the ```permanent``` option is set to "true", the worker will automatically terminate itself when its task is complete. 

> - **constructor** ```(pool: WorkerThreadPool, fileName: string, options? object)```
Sets the thread pool that this worker will be assigned to and builds the WebWorker plus its default actions. Finally it stores this worker in the thread pool for later use.
> - **postDirectMessage** ```(data?: object): void```
Directly posts a message to the WebWorker without the help of the thread pool. This might interfere with the performance since it could possible execute when the threads are overloaded.
>- **postMessage** ```(data?: object, resolve?: void): void```
Tells this worker what data to send and what to do when the its task is completed. Once called, it will send this worker to the thread pool to either be queued or executed based on how many threads are currently busy.
>- **terminate** ```(): void```
Gets rid of this worker from memory.


## Usage

There are a couple ways to use this, but below is the way it was intended

```javascript
import { WorkerThreadPool } from '@little-island/ecs'

// let's create the thread pool we are tell it to only queue a max of 2 workers at once.
// This usually defaults to the number of threads your CPU has available.

const ThreadPool = new WorkerThreadPool( { maxUsableThreads: 2 } )

//-------------------------
/** Define some workers */
//-----------------------

// this worker takes two numbers and multiplies them together and squares them (it's a module by default).
const Worker1 = ThreadPool.createWorker( './workers/mathThing.js' )

//this worker takes an array and reverses the order of its contents and adds "animal:" to the beginning of each one.
const Worker2 = ThreadPool.createWorker( './workers/animals.js', { type: 'classic' } )

//this worker just posts "Hello wide world!".
const Worker3 = ThreadPool.createWorker( './workers/hello-world.js', { type: 'module' } )

//this worker just posts "I will stay here..." and is permanent.
const Worker4 = ThreadPool.createWorker( './workers/mr-steady.js', { permanent: true, type: 'module' } )

//-----------------------------------------------
/** Execute and send workers to do some tasks */
//---------------------------------------------

 // e.result is 784
Worker1.postMessage( { num1: 7, num2: 4 }, ( e ) => { console.log( e.result ) } )

 // e.newArray is [ "animal:fish", "animal:cat", "animal:dog" ]
Worker2.postMessage( [ 'dog', 'cat', 'fish' ], ( e ) => { console.log( e.newArray ) } )

// this worker will be queued since all 2 threads allowed have are being occupied by the previous workers.
// Once one of the first 2 finishes its task, this worker will be removed from the queue and will be executed.

// e.message is "Hello wide world!"
Worker3.postMessage( {}, ( e ) => { console.log( e.message ) } )

// this worker runs the same way as Worker3.
// Unlike all the other workers we made though, this one will stay busy until we decide to manually terminate it.

// e.message is "I will stay here..."
Worker4.postMessage( {}, ( e ) => { console.log( e.message ) } )

```