Farm.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. var _types = require('./types');
  7. function _defineProperty(obj, key, value) {
  8. if (key in obj) {
  9. Object.defineProperty(obj, key, {
  10. value: value,
  11. enumerable: true,
  12. configurable: true,
  13. writable: true
  14. });
  15. } else {
  16. obj[key] = value;
  17. }
  18. return obj;
  19. }
  20. class Farm {
  21. constructor(numOfWorkers, callback, computeWorkerKey) {
  22. _defineProperty(this, '_computeWorkerKey', void 0);
  23. _defineProperty(this, '_cacheKeys', void 0);
  24. _defineProperty(this, '_callback', void 0);
  25. _defineProperty(this, '_last', void 0);
  26. _defineProperty(this, '_locks', void 0);
  27. _defineProperty(this, '_numOfWorkers', void 0);
  28. _defineProperty(this, '_offset', void 0);
  29. _defineProperty(this, '_queue', void 0);
  30. this._cacheKeys = Object.create(null);
  31. this._callback = callback;
  32. this._last = [];
  33. this._locks = [];
  34. this._numOfWorkers = numOfWorkers;
  35. this._offset = 0;
  36. this._queue = [];
  37. if (computeWorkerKey) {
  38. this._computeWorkerKey = computeWorkerKey;
  39. }
  40. }
  41. doWork(method, ...args) {
  42. const customMessageListeners = new Set();
  43. const addCustomMessageListener = listener => {
  44. customMessageListeners.add(listener);
  45. return () => {
  46. customMessageListeners.delete(listener);
  47. };
  48. };
  49. const onCustomMessage = message => {
  50. customMessageListeners.forEach(listener => listener(message));
  51. };
  52. const promise = new Promise((resolve, reject) => {
  53. const computeWorkerKey = this._computeWorkerKey;
  54. const request = [_types.CHILD_MESSAGE_CALL, false, method, args];
  55. let worker = null;
  56. let hash = null;
  57. if (computeWorkerKey) {
  58. hash = computeWorkerKey.call(this, method, ...args);
  59. worker = hash == null ? null : this._cacheKeys[hash];
  60. }
  61. const onStart = worker => {
  62. if (hash != null) {
  63. this._cacheKeys[hash] = worker;
  64. }
  65. };
  66. const onEnd = (error, result) => {
  67. customMessageListeners.clear();
  68. if (error) {
  69. reject(error);
  70. } else {
  71. resolve(result);
  72. }
  73. };
  74. const task = {
  75. onCustomMessage,
  76. onEnd,
  77. onStart,
  78. request
  79. };
  80. if (worker) {
  81. this._enqueue(task, worker.getWorkerId());
  82. } else {
  83. this._push(task);
  84. }
  85. });
  86. promise.UNSTABLE_onCustomMessage = addCustomMessageListener;
  87. return promise;
  88. }
  89. _getNextTask(workerId) {
  90. let queueHead = this._queue[workerId];
  91. while (queueHead && queueHead.task.request[1]) {
  92. queueHead = queueHead.next || null;
  93. }
  94. this._queue[workerId] = queueHead;
  95. return queueHead && queueHead.task;
  96. }
  97. _process(workerId) {
  98. if (this._isLocked(workerId)) {
  99. return this;
  100. }
  101. const task = this._getNextTask(workerId);
  102. if (!task) {
  103. return this;
  104. }
  105. const onEnd = (error, result) => {
  106. task.onEnd(error, result);
  107. this._unlock(workerId);
  108. this._process(workerId);
  109. };
  110. task.request[1] = true;
  111. this._lock(workerId);
  112. this._callback(
  113. workerId,
  114. task.request,
  115. task.onStart,
  116. onEnd,
  117. task.onCustomMessage
  118. );
  119. return this;
  120. }
  121. _enqueue(task, workerId) {
  122. const item = {
  123. next: null,
  124. task
  125. };
  126. if (task.request[1]) {
  127. return this;
  128. }
  129. if (this._queue[workerId]) {
  130. this._last[workerId].next = item;
  131. } else {
  132. this._queue[workerId] = item;
  133. }
  134. this._last[workerId] = item;
  135. this._process(workerId);
  136. return this;
  137. }
  138. _push(task) {
  139. for (let i = 0; i < this._numOfWorkers; i++) {
  140. this._enqueue(task, (this._offset + i) % this._numOfWorkers);
  141. }
  142. this._offset++;
  143. return this;
  144. }
  145. _lock(workerId) {
  146. this._locks[workerId] = true;
  147. }
  148. _unlock(workerId) {
  149. this._locks[workerId] = false;
  150. }
  151. _isLocked(workerId) {
  152. return this._locks[workerId];
  153. }
  154. }
  155. exports.default = Farm;