import defaultValue from '../Core/defaultValue.js'; import defined from '../Core/defined.js'; import formatError from '../Core/formatError.js'; import when from '../ThirdParty/when.js'; // createXXXGeometry functions may return Geometry or a Promise that resolves to Geometry // if the function requires access to ApproximateTerrainHeights. // For fully synchronous functions, just wrapping the function call in a `when` Promise doesn't // handle errors correctly, hence try-catch function callAndWrap(workerFunction, parameters, transferableObjects) { var resultOrPromise; try { resultOrPromise = workerFunction(parameters, transferableObjects); return resultOrPromise; // errors handled by Promise } catch (e) { return when.reject(e); } } /** * Creates an adapter function to allow a calculation function to operate as a Web Worker, * paired with TaskProcessor, to receive tasks and return results. * * @exports createTaskProcessorWorker * * @param {createTaskProcessorWorker~WorkerFunction} workerFunction The calculation function, * which takes parameters and returns a result. * @returns {createTaskProcessorWorker~TaskProcessorWorkerFunction} A function that adapts the * calculation function to work as a Web Worker onmessage listener with TaskProcessor. * * * @example * function doCalculation(parameters, transferableObjects) { * // calculate some result using the inputs in parameters * return result; * } * * return Cesium.createTaskProcessorWorker(doCalculation); * // the resulting function is compatible with TaskProcessor * * @see TaskProcessor * @see {@link http://www.w3.org/TR/workers/|Web Workers} * @see {@link http://www.w3.org/TR/html5/common-dom-interfaces.html#transferable-objects|Transferable objects} */ function createTaskProcessorWorker(workerFunction) { var postMessage; return function(event) { var data = event.data; var transferableObjects = []; var responseMessage = { id : data.id, result : undefined, error : undefined }; return when(callAndWrap(workerFunction, data.parameters, transferableObjects)) .then(function(result) { responseMessage.result = result; }) .otherwise(function(e) { if (e instanceof Error) { // Errors can't be posted in a message, copy the properties responseMessage.error = { name : e.name, message : e.message, stack : e.stack }; } else { responseMessage.error = e; } }) .always(function() { if (!defined(postMessage)) { postMessage = defaultValue(self.webkitPostMessage, self.postMessage); } if (!data.canTransferArrayBuffer) { transferableObjects.length = 0; } try { postMessage(responseMessage, transferableObjects); } catch (e) { // something went wrong trying to post the message, post a simpler // error that we can be sure will be cloneable responseMessage.result = undefined; responseMessage.error = 'postMessage failed with error: ' + formatError(e) + '\n with responseMessage: ' + JSON.stringify(responseMessage); postMessage(responseMessage); } }); }; } /** * A function that performs a calculation in a Web Worker. * @callback createTaskProcessorWorker~WorkerFunction * * @param {Object} parameters Parameters to the calculation. * @param {Array} transferableObjects An array that should be filled with references to objects inside * the result that should be transferred back to the main document instead of copied. * @returns {Object} The result of the calculation. * * @example * function calculate(parameters, transferableObjects) { * // perform whatever calculation is necessary. * var typedArray = new Float32Array(0); * * // typed arrays are transferable * transferableObjects.push(typedArray) * * return { * typedArray : typedArray * }; * } */ /** * A Web Worker message event handler function that handles the interaction with TaskProcessor, * specifically, task ID management and posting a response message containing the result. * @callback createTaskProcessorWorker~TaskProcessorWorkerFunction * * @param {Object} event The onmessage event object. */ export default createTaskProcessorWorker;