/** * @author Deepkolos / https://github.com/deepkolos */ export class WorkerPool { constructor ( pool = 4 ) { this.pool = pool; this.queue = []; this.workers = []; this.workersResolve = []; this.workerStatus = 0; } _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; } } setWorkerCreator ( workerCreator ) { this.workerCreator = workerCreator; } setWorkerLimit ( pool ) { this.pool = pool; } 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 () { this.workers.forEach( ( worker ) => worker.terminate() ); this.workersResolve.length = 0; this.workers.length = 0; this.queue.length = 0; this.workerStatus = 0; } }