Skip to content

⬅️ Back to Table of Contents

📄 WorkerPool.js

📊 Analysis Summary

Metric Count
🔧 Functions 7
🧱 Classes 1
📊 Variables & Constants 1

📚 Table of Contents

🛠️ File Location:

📂 examples/jsm/utils/WorkerPool.js

Variables & Constants

Name Type Kind Value Exported
resolve Function let/var this.workersResolve[ workerId ]

Functions

WorkerPool._initWorker(workerId: any): void

Parameters:

  • workerId any

Returns: void

Calls:

  • this.workerCreator
  • worker.addEventListener
  • this._onMessage.bind
Code
_initWorker( workerId ) {

        if ( ! this.workers[ workerId ] ) {

            const worker = this.workerCreator();
            worker.addEventListener( 'message', this._onMessage.bind( this, workerId ) );
            this.workers[ workerId ] = worker;

        }

    }

WorkerPool._getIdleWorker(): number

Returns: number

Code
_getIdleWorker() {

        for ( let i = 0; i < this.pool; i ++ )
            if ( ! ( this.workerStatus & ( 1 << i ) ) ) return i;

        return - 1;

    }

WorkerPool._onMessage(workerId: any, msg: any): void

Parameters:

  • workerId any
  • msg any

Returns: void

Calls:

  • resolve
  • this.queue.shift
  • this.workers[ workerId ].postMessage
Code
_onMessage( workerId, msg ) {

        const resolve = this.workersResolve[ workerId ];
        resolve && resolve( msg );

        if ( this.queue.length ) {

            const { resolve, msg, transfer } = this.queue.shift();
            this.workersResolve[ workerId ] = resolve;
            this.workers[ workerId ].postMessage( msg, transfer );

        } else {

            this.workerStatus ^= 1 << workerId;

        }

    }

WorkerPool.setWorkerCreator(workerCreator: Function): void

JSDoc:

/**
     * Sets a function that is responsible for creating Workers.
     *
     * @param {Function} workerCreator - The worker creator function.
     */

Parameters:

  • workerCreator Function

Returns: void

Code
setWorkerCreator( workerCreator ) {

        this.workerCreator = workerCreator;

    }

WorkerPool.setWorkerLimit(pool: number): void

JSDoc:

/**
     * Sets the Worker limit
     *
     * @param {number} pool - The size of the pool.
     */

Parameters:

  • pool number

Returns: void

Code
setWorkerLimit( pool ) {

        this.pool = pool;

    }

WorkerPool.postMessage(msg: any, transfer: ArrayBuffer[]): Promise<any>

JSDoc:

/**
     * Post a message to an idle Worker. If no Worker is available,
     * the message is pushed into a message queue for later processing.
     *
     * @param {Object} msg - The message.
     * @param {Array<ArrayBuffer>} transfer - An array with array buffers for data transfer.
     * @return {Promise} A Promise that resolves when the message has been processed.
     */

Parameters:

  • msg any
  • transfer ArrayBuffer[]

Returns: Promise<any>

Calls:

  • this._getIdleWorker
  • this._initWorker
  • this.workers[ workerId ].postMessage
  • this.queue.push
Code
postMessage( msg, transfer ) {

        return new Promise( ( resolve ) => {

            const workerId = this._getIdleWorker();

            if ( workerId !== - 1 ) {

                this._initWorker( workerId );
                this.workerStatus |= 1 << workerId;
                this.workersResolve[ workerId ] = resolve;
                this.workers[ workerId ].postMessage( msg, transfer );

            } else {

                this.queue.push( { resolve, msg, transfer } );

            }

        } );

    }

WorkerPool.dispose(): void

JSDoc:

/**
     * Terminates all Workers of this pool. Call this  method whenever this
     * Worker pool is no longer used in your app.
     */

Returns: void

Calls:

  • this.workers.forEach
  • worker.terminate
Code
dispose() {

        this.workers.forEach( ( worker ) => worker.terminate() );
        this.workersResolve.length = 0;
        this.workers.length = 0;
        this.queue.length = 0;
        this.workerStatus = 0;

    }

Classes

WorkerPool

Class Code
export class WorkerPool {

    /**
     * Constructs a new Worker pool.
     *
     * @param {number} [pool=4] - The size of the pool.
     */
    constructor( pool = 4 ) {

        /**
         * The size of the pool.
         *
         * @type {number}
         * @default 4
         */
        this.pool = pool;

        /**
         * A message queue.
         *
         * @type {Array<Object>}
         */
        this.queue = [];

        /**
         * An array of Workers.
         *
         * @type {Array<Worker>}
         */
        this.workers = [];

        /**
         * An array with resolve functions for messages.
         *
         * @type {Array<Function>}
         */
        this.workersResolve = [];

        /**
         * The current worker status.
         *
         * @type {number}
         */
        this.workerStatus = 0;

        /**
         * A factory function for creating workers.
         *
         * @type {?Function}
         */
        this.workerCreator = null;

    }

    _initWorker( workerId ) {

        if ( ! this.workers[ workerId ] ) {

            const worker = this.workerCreator();
            worker.addEventListener( 'message', this._onMessage.bind( this, workerId ) );
            this.workers[ workerId ] = worker;

        }

    }

    _getIdleWorker() {

        for ( let i = 0; i < this.pool; i ++ )
            if ( ! ( this.workerStatus & ( 1 << i ) ) ) return i;

        return - 1;

    }

    _onMessage( workerId, msg ) {

        const resolve = this.workersResolve[ workerId ];
        resolve && resolve( msg );

        if ( this.queue.length ) {

            const { resolve, msg, transfer } = this.queue.shift();
            this.workersResolve[ workerId ] = resolve;
            this.workers[ workerId ].postMessage( msg, transfer );

        } else {

            this.workerStatus ^= 1 << workerId;

        }

    }

    /**
     * Sets a function that is responsible for creating Workers.
     *
     * @param {Function} workerCreator - The worker creator function.
     */
    setWorkerCreator( workerCreator ) {

        this.workerCreator = workerCreator;

    }

    /**
     * Sets the Worker limit
     *
     * @param {number} pool - The size of the pool.
     */
    setWorkerLimit( pool ) {

        this.pool = pool;

    }

    /**
     * Post a message to an idle Worker. If no Worker is available,
     * the message is pushed into a message queue for later processing.
     *
     * @param {Object} msg - The message.
     * @param {Array<ArrayBuffer>} transfer - An array with array buffers for data transfer.
     * @return {Promise} A Promise that resolves when the message has been processed.
     */
    postMessage( msg, transfer ) {

        return new Promise( ( resolve ) => {

            const workerId = this._getIdleWorker();

            if ( workerId !== - 1 ) {

                this._initWorker( workerId );
                this.workerStatus |= 1 << workerId;
                this.workersResolve[ workerId ] = resolve;
                this.workers[ workerId ].postMessage( msg, transfer );

            } else {

                this.queue.push( { resolve, msg, transfer } );

            }

        } );

    }

    /**
     * Terminates all Workers of this pool. Call this  method whenever this
     * Worker pool is no longer used in your app.
     */
    dispose() {

        this.workers.forEach( ( worker ) => worker.terminate() );
        this.workersResolve.length = 0;
        this.workers.length = 0;
        this.queue.length = 0;
        this.workerStatus = 0;

    }

}

Methods

_initWorker(workerId: any): void
Code
_initWorker( workerId ) {

        if ( ! this.workers[ workerId ] ) {

            const worker = this.workerCreator();
            worker.addEventListener( 'message', this._onMessage.bind( this, workerId ) );
            this.workers[ workerId ] = worker;

        }

    }
_getIdleWorker(): number
Code
_getIdleWorker() {

        for ( let i = 0; i < this.pool; i ++ )
            if ( ! ( this.workerStatus & ( 1 << i ) ) ) return i;

        return - 1;

    }
_onMessage(workerId: any, msg: any): void
Code
_onMessage( workerId, msg ) {

        const resolve = this.workersResolve[ workerId ];
        resolve && resolve( msg );

        if ( this.queue.length ) {

            const { resolve, msg, transfer } = this.queue.shift();
            this.workersResolve[ workerId ] = resolve;
            this.workers[ workerId ].postMessage( msg, transfer );

        } else {

            this.workerStatus ^= 1 << workerId;

        }

    }
setWorkerCreator(workerCreator: Function): void
Code
setWorkerCreator( workerCreator ) {

        this.workerCreator = workerCreator;

    }
setWorkerLimit(pool: number): void
Code
setWorkerLimit( pool ) {

        this.pool = pool;

    }
postMessage(msg: any, transfer: ArrayBuffer[]): Promise<any>
Code
postMessage( msg, transfer ) {

        return new Promise( ( resolve ) => {

            const workerId = this._getIdleWorker();

            if ( workerId !== - 1 ) {

                this._initWorker( workerId );
                this.workerStatus |= 1 << workerId;
                this.workersResolve[ workerId ] = resolve;
                this.workers[ workerId ].postMessage( msg, transfer );

            } else {

                this.queue.push( { resolve, msg, transfer } );

            }

        } );

    }
dispose(): void
Code
dispose() {

        this.workers.forEach( ( worker ) => worker.terminate() );
        this.workersResolve.length = 0;
        this.workers.length = 0;
        this.queue.length = 0;
        this.workerStatus = 0;

    }