Source: util/workers/WebWorker.js

export class WebWorker {

    /**
     * @alias WebWorker
     * @constructor
     * @param {*} Loader a webpack worker-loader
     * @param {Function} onMessage 
     * @param {Function} onError 
     */
    constructor(Loader, onMessage, onError) {
        this.Loader = Loader;
        
        this.inProgress = false;
        
        this.workId = null;
        
        this.worker = null;

        this.terminateTimeout = null;

        this.onMessage = this.onMessage.bind(this);
        this.onError = this.onError.bind(this);

        this.onMessageCallback = onMessage;
        this.onErrorCallback = onError;
    }

    /**
     * Sends data to the web worker.
     * 
     * @param {*} data 
     * @param {*} id 
     */
    postMessage(data, id) {
        if (!this.worker) {
            this.start();
        }
        this.worker.postMessage(data);
        this.inProgress = true;
        this.workId = id;
    }

    /**
     * Initializes a web worker.
     */
    start() {
        if (this.worker) {
            return;
        }
        this.worker = new this.Loader();
        this.bindEvents();
    }

    /**
    * Terminates a web worker.
    */
    stop() {
        if (this.worker) {
            if (this.inProgress) {
                this.scheduleTerminate();
                return false;
            }
            this.unbindEvents();
            this.worker.terminate();
            this.worker = null;
            this.inProgress = false;
        }
        return true;
    }

    bindEvents() {
        this.worker.addEventListener('message', this.onMessage, false);
        this.worker.addEventListener('error', this.onError, false);
    }

    unbindEvents() {
        this.worker.removeEventListener('message', this.onMessage);
        this.worker.removeEventListener('error', this.onError);
    }

    scheduleTerminate() {
        clearTimeout(this.terminateTimeout);
        this.terminateTimeout = setTimeout(() => {
            this.stop();
        }, 5000);
    }

    onMessage(e) {
        this.inProgress = false;
        this.onMessageCallback(e.data, this.workId);
    }

    onError(e) {
        this.inProgress = false;
        this.onErrorCallback(e, this.workId);
    }

}