all files / src/ index.js

97.37% Statements 37/38
81.25% Branches 13/16
100% Functions 10/10
97.37% Lines 37/38
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109                                                 15×                                           18× 18× 18× 18×                 28×     27×   26× 20× 20×           20× 20×   20×                    
const TinyEmitter = require('./tiny-emitter');
 
const MESSAGE_RESULT = 0;
const MESSAGE_EVENT = 1;
 
const RESULT_ERROR = 0;
const RESULT_SUCCESS = 1;
 
class Worker extends TinyEmitter {
  /**
   *
   * @param worker {Worker}
   */
  constructor(worker) {
    super();
 
    this._messageId = 1;
    this._messages = new Map();
 
    this._worker = worker;
    this._worker.onmessage = this._onMessage.bind(this);
    this._id = Math.ceil(Math.random() * 10000000);
  }
 
  terminate() {
    this._worker.terminate();
  }
 
  /**
   * return true if there is no unresolved jobs
   * @returns {boolean}
   */
  isFree() {
    return this._messages.size === 0;
  }
 
  jobsLength() {
    return this._messages.size;
  }
 
  /**
   * @param operationName string
   * @param data any
   * @param transferable array
   * @param onEvent function
   * @returns {Promise}
   */
  exec(operationName, data = null, transferable = [], onEvent) {
    return new Promise((res, rej) => {
      const messageId = this._messageId++;
      this._messages.set(messageId, [res, rej, onEvent]);
      this._worker.postMessage([messageId, data, operationName], transferable || []);
    });
  }
 
  /**
   *
   * @param data any
   * @param transferable array
   * @param onEvent function
   * @returns {Promise}
   */
  postMessage(data = null, transferable = [], onEvent) {
    return new Promise((res, rej) => {
      const messageId = this._messageId++;
      this._messages.set(messageId, [res, rej, onEvent]);
      this._worker.postMessage([messageId, data], transferable || []);
    });
  }
 
  emit(eventName, ...args) {
    this._worker.postMessage({eventName, args});
  }
 
  _onMessage(e) {
    //if we got usual event, just emit it locally
    if(!Array.isArray(e.data) && e.data.eventName) {
      return super.emit(e.data.eventName, ...e.data.args);
    }
 
    const [type, ...args] = e.data;
 
    if(type === MESSAGE_EVENT)
      this._onEvent(...args);
    else Eif(type === MESSAGE_RESULT)
      this._onResult(...args);
    else
      throw new Error(`Wrong message type '${type}'`);
  }
 
  _onResult(messageId, success, payload) {
    const [res, rej] = this._messages.get(messageId);
    this._messages.delete(messageId);
 
    return success === RESULT_SUCCESS ? res(payload) : rej(payload);
  }
 
  _onEvent(messageId, eventName, data) {
    const [,,onEvent] = this._messages.get(messageId);
 
    if(onEvent) {
      onEvent(eventName, data);
    }
  }
 
}
 
module.exports = Worker;