You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					204 lines
				
				4.0 KiB
			
		
		
			
		
	
	
					204 lines
				
				4.0 KiB
			| 
											3 years ago
										 | 'use strict'; | ||
|  | 
 | ||
|  | Object.defineProperty(exports, '__esModule', { | ||
|  |   value: true | ||
|  | }); | ||
|  | exports.default = void 0; | ||
|  | 
 | ||
|  | var _types = require('./types'); | ||
|  | 
 | ||
|  | function _defineProperty(obj, key, value) { | ||
|  |   if (key in obj) { | ||
|  |     Object.defineProperty(obj, key, { | ||
|  |       value: value, | ||
|  |       enumerable: true, | ||
|  |       configurable: true, | ||
|  |       writable: true | ||
|  |     }); | ||
|  |   } else { | ||
|  |     obj[key] = value; | ||
|  |   } | ||
|  |   return obj; | ||
|  | } | ||
|  | 
 | ||
|  | class Farm { | ||
|  |   constructor(numOfWorkers, callback, computeWorkerKey) { | ||
|  |     _defineProperty(this, '_computeWorkerKey', void 0); | ||
|  | 
 | ||
|  |     _defineProperty(this, '_cacheKeys', void 0); | ||
|  | 
 | ||
|  |     _defineProperty(this, '_callback', void 0); | ||
|  | 
 | ||
|  |     _defineProperty(this, '_last', void 0); | ||
|  | 
 | ||
|  |     _defineProperty(this, '_locks', void 0); | ||
|  | 
 | ||
|  |     _defineProperty(this, '_numOfWorkers', void 0); | ||
|  | 
 | ||
|  |     _defineProperty(this, '_offset', void 0); | ||
|  | 
 | ||
|  |     _defineProperty(this, '_queue', void 0); | ||
|  | 
 | ||
|  |     this._cacheKeys = Object.create(null); | ||
|  |     this._callback = callback; | ||
|  |     this._last = []; | ||
|  |     this._locks = []; | ||
|  |     this._numOfWorkers = numOfWorkers; | ||
|  |     this._offset = 0; | ||
|  |     this._queue = []; | ||
|  | 
 | ||
|  |     if (computeWorkerKey) { | ||
|  |       this._computeWorkerKey = computeWorkerKey; | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   doWork(method, ...args) { | ||
|  |     const customMessageListeners = new Set(); | ||
|  | 
 | ||
|  |     const addCustomMessageListener = listener => { | ||
|  |       customMessageListeners.add(listener); | ||
|  |       return () => { | ||
|  |         customMessageListeners.delete(listener); | ||
|  |       }; | ||
|  |     }; | ||
|  | 
 | ||
|  |     const onCustomMessage = message => { | ||
|  |       customMessageListeners.forEach(listener => listener(message)); | ||
|  |     }; | ||
|  | 
 | ||
|  |     const promise = new Promise((resolve, reject) => { | ||
|  |       const computeWorkerKey = this._computeWorkerKey; | ||
|  |       const request = [_types.CHILD_MESSAGE_CALL, false, method, args]; | ||
|  |       let worker = null; | ||
|  |       let hash = null; | ||
|  | 
 | ||
|  |       if (computeWorkerKey) { | ||
|  |         hash = computeWorkerKey.call(this, method, ...args); | ||
|  |         worker = hash == null ? null : this._cacheKeys[hash]; | ||
|  |       } | ||
|  | 
 | ||
|  |       const onStart = worker => { | ||
|  |         if (hash != null) { | ||
|  |           this._cacheKeys[hash] = worker; | ||
|  |         } | ||
|  |       }; | ||
|  | 
 | ||
|  |       const onEnd = (error, result) => { | ||
|  |         customMessageListeners.clear(); | ||
|  | 
 | ||
|  |         if (error) { | ||
|  |           reject(error); | ||
|  |         } else { | ||
|  |           resolve(result); | ||
|  |         } | ||
|  |       }; | ||
|  | 
 | ||
|  |       const task = { | ||
|  |         onCustomMessage, | ||
|  |         onEnd, | ||
|  |         onStart, | ||
|  |         request | ||
|  |       }; | ||
|  | 
 | ||
|  |       if (worker) { | ||
|  |         this._enqueue(task, worker.getWorkerId()); | ||
|  |       } else { | ||
|  |         this._push(task); | ||
|  |       } | ||
|  |     }); | ||
|  |     promise.UNSTABLE_onCustomMessage = addCustomMessageListener; | ||
|  |     return promise; | ||
|  |   } | ||
|  | 
 | ||
|  |   _getNextTask(workerId) { | ||
|  |     let queueHead = this._queue[workerId]; | ||
|  | 
 | ||
|  |     while (queueHead && queueHead.task.request[1]) { | ||
|  |       queueHead = queueHead.next || null; | ||
|  |     } | ||
|  | 
 | ||
|  |     this._queue[workerId] = queueHead; | ||
|  |     return queueHead && queueHead.task; | ||
|  |   } | ||
|  | 
 | ||
|  |   _process(workerId) { | ||
|  |     if (this._isLocked(workerId)) { | ||
|  |       return this; | ||
|  |     } | ||
|  | 
 | ||
|  |     const task = this._getNextTask(workerId); | ||
|  | 
 | ||
|  |     if (!task) { | ||
|  |       return this; | ||
|  |     } | ||
|  | 
 | ||
|  |     const onEnd = (error, result) => { | ||
|  |       task.onEnd(error, result); | ||
|  | 
 | ||
|  |       this._unlock(workerId); | ||
|  | 
 | ||
|  |       this._process(workerId); | ||
|  |     }; | ||
|  | 
 | ||
|  |     task.request[1] = true; | ||
|  | 
 | ||
|  |     this._lock(workerId); | ||
|  | 
 | ||
|  |     this._callback( | ||
|  |       workerId, | ||
|  |       task.request, | ||
|  |       task.onStart, | ||
|  |       onEnd, | ||
|  |       task.onCustomMessage | ||
|  |     ); | ||
|  | 
 | ||
|  |     return this; | ||
|  |   } | ||
|  | 
 | ||
|  |   _enqueue(task, workerId) { | ||
|  |     const item = { | ||
|  |       next: null, | ||
|  |       task | ||
|  |     }; | ||
|  | 
 | ||
|  |     if (task.request[1]) { | ||
|  |       return this; | ||
|  |     } | ||
|  | 
 | ||
|  |     if (this._queue[workerId]) { | ||
|  |       this._last[workerId].next = item; | ||
|  |     } else { | ||
|  |       this._queue[workerId] = item; | ||
|  |     } | ||
|  | 
 | ||
|  |     this._last[workerId] = item; | ||
|  | 
 | ||
|  |     this._process(workerId); | ||
|  | 
 | ||
|  |     return this; | ||
|  |   } | ||
|  | 
 | ||
|  |   _push(task) { | ||
|  |     for (let i = 0; i < this._numOfWorkers; i++) { | ||
|  |       this._enqueue(task, (this._offset + i) % this._numOfWorkers); | ||
|  |     } | ||
|  | 
 | ||
|  |     this._offset++; | ||
|  |     return this; | ||
|  |   } | ||
|  | 
 | ||
|  |   _lock(workerId) { | ||
|  |     this._locks[workerId] = true; | ||
|  |   } | ||
|  | 
 | ||
|  |   _unlock(workerId) { | ||
|  |     this._locks[workerId] = false; | ||
|  |   } | ||
|  | 
 | ||
|  |   _isLocked(workerId) { | ||
|  |     return this._locks[workerId]; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | exports.default = Farm; |