UNPKG

@arcgis/core

Version:

ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API

271 lines (269 loc) • 10.4 kB
import type { AbortOptions } from "../promiseUtils.js"; /** An object specifying additional options when calling [invoke()](https://developers.arcgis.com/javascript/latest/references/core/core/workers/Connection/#invoke) method. */ export interface InvokeOptions extends AbortOptions { /** * An array of Transferable * objects. Each transferable object in the array should have a corresponding entry in the data object. * See [Using transferables](https://developers.arcgis.com/javascript/latest/references/core/core/workers/Connection/#using-transferables) section for more information. */ transferList?: Transferable[]; } /** * This class is used to execute remote methods located on the module loaded into a separate thread via * the [workers framework](https://developers.arcgis.com/javascript/latest/references/core/core/workers/). * * The [open()](https://developers.arcgis.com/javascript/latest/references/core/core/workers/#open) method loads the * script and returns a Promise * to the main thread. Once resolved, you gain access to an instance of Connection, which allows you to call * methods of the module via [invoke()](https://developers.arcgis.com/javascript/latest/references/core/core/workers/Connection/#invoke) or [broadcast()](https://developers.arcgis.com/javascript/latest/references/core/core/workers/Connection/#broadcast) methods. * * <span id="basic-invocation"></span> * ## Invoking a remote method * * To delegate work to a worker, you need to create a module that exposes functions * or a class that will be instantiated by the framework. * Each remote method can accept one parameter only. The parameter value can be any * [primitive type](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Primitive_values), * or JavaScript object handled by the * [structured clone algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm), * or a [JavaScript Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) * that resolves with one of them. * * For example, let's create a simple worker that calculates the sum of an array of numbers. * * ```js * // Module loaded in worker : calculator.js * export function getSum(numbers) { * let sum = 0; * * for (let i = 0; i < numbers.length; i++) { * sum += numbers[i]; * } * * return sum; * } * ``` * * Now we load the calculator module into a worker and invoke its `getSum` function. * * ```js * // Module loaded in main thread * export function getSumAsync(numbers) { * let connection = null; * * return workers.open("./calculator.js") * .then(function(conn) { * // Keep the connection reference to later close it. * connection = conn; * * return connection.invoke("getSum", numbers); * }) * .then(function(result) { * // close the connection * connection.close(); * connection = null; * * return result; * }); * } * * // Invoke our method. * getSumAsync([0, 2, 4, 6, 8]) * .then(function(result) { * console.log("Result:", result); * }); * ``` * * <span id="multiple-parameters"></span> * ## Passing multiple parameters * * As mentioned above, the remote methods loaded with worker can only accept one parameter. * However, to pass multiple parameters to the remote method, use a JavaScript object with multiple key-value pairs. * * The example below shows a function that multiplies an array of numbers by a factor. * * ```js * // Module loaded in worker : calculator.js * export function mapMultiply(params) { * // params has numbers and factor values. * let numbers = params.numbers; * let factor = params.factor; * * for (let i = 0; i < numbers.length; i++) { * numbers[i] *= factor; * } * * return numbers; * } * ``` * * To invoke this function, an object with two properties is passed into the function. * * ```js * // Module loaded in main thread * export function mapMultiplyAsync(numbers, factor) { * let connection = null; * * return workers.open("./calculator.js") * .then(function(conn) { * // Keep the connection reference to later close it. * connection = conn; * * // invoke mapMultiply and pass in object with two key-value pairs. * return connection.invoke("mapMultiply", { * numbers: numbers, * factor: factor * }); * }) * .then(function(result) { * // close the connection after we are done. * connection.close(); * connection = null; * * return result; * }); * } * * // Invoke the method. * mapMultiplyAsync([0, 2, 4, 6, 8], 2) * .then(function(result) { * console.log("Result:", result); * }); * ``` * * <span id="using-transferables"></span> * ## Using transferables * * `Transferable` objects can be used * to transfer data between main and worker thread to avoid copying the data. With this approach, * the ownership of the object is transferred to the other context. Use this technique to transfer large * chuck of memory with [ArrayBuffers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer), * a [MessagePort](https://developer.mozilla.org/en-US/docs/Web/API/MessagePort), * or an [ImageBitmap](https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap). * * > [!CAUTION] * > * > **Note** * > * > The `Transferable` interface technically no longer exists. The functionality of `Transferable` objects still exists, * > however, but is implemented at a more fundamental level * > (technically speaking, using the `[Transferable]` [WebIDL](https://developer.mozilla.org/en-US/docs/Glossary/WebIDL) * > extended attribute). See also [Transferable objects](https://developer.mozilla.org/en-US/docs/Glossary/Transferable_objects). * * To transfer an object to the worker, use the `transferList` parameter of the [invoke()](https://developers.arcgis.com/javascript/latest/references/core/core/workers/Connection/#invoke) method. * For the remote method to return or resolve with a transferable object, the result returned must have * two properties: `result` and `transferList`, `result` being an object and `transferList` the array * of transferable objects. Note that every transferable object in `transferList` should be in the object structure * of `result`. * * Let's revisit the previous example to explore transferable objects. * * ```js * // Module loaded in worker : calculator.js * export function mapMultiplyFloat64(params) { * // the numbers parameter is an ArrayBuffer * // we create a typed array from it. * let numbers = new Float64Array(params.numbers); * let factor = params.factor; * * for (let i = 0; i < numbers.length; i++) { * numbers[i] *= factor; * } * * // Transfer back the buffer * return { * result: numbers.buffer, * transferList: [numbers.buffer] * }; * } * ``` * * On the main thread, we transfer the input typed array's buffer. * Then we recreate a [Float64Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float64Array) back from the returned buffer. * * ```js * // Module loaded in main thread * export function mapMultiplyFloat64Async(numbers, factor) { * let connection = null; * * return workers.open("./calculator.js") * .then(function(conn) { * // Keep the connection reference to later close it. * connection = conn; * * return connection.invoke("mapMultiplyFloat64", { * numbers: numbers, * factor: factor * }); * }) * .then(function(result) { * // close the connection after we are done. * connection.close(); * connection = null; * * return result; * }); * } * * // Invoke our method. * let floats = new Float64Array(5); * floats[0] = 0; * floats[1] = 2; * floats[2] = 4; * floats[3] = 6; * floats[4] = 8; * mapMultiplyFloat64Async(floats, 2) * .then(function(result) { * let resultFloats = new Float64Array(result); * console.log("Result:", resultFloats); * }); * ``` * * @since 4.2 */ export default abstract class Connection { /** * A convenient method that invokes a method on each worker. * * @param methodName - The name of the remote method to invoke on all workers. * @param data - The unique parameter passed as argument of the remote method. * @param options - An object specifying additional options. See the * object specification table below for the required properties of this object. * @returns An array of promises that resolves with the result of the execution on each worker. */ broadcast<T>(methodName: string, data?: any, options?: AbortOptions): Promise<T>[]; /** * Closes the existing connection instance to workers. * Notifies all workers to destroy the connection instance and dispose the remote module. */ close(): void; /** * Invokes a [method](https://developers.arcgis.com/javascript/latest/references/core/core/workers/Connection/#basic-invocation) on the remote module loaded with the worker. * * @param methodName - The name of the method to be invoked in the script. * @param data - The unique parameter passed as argument of the remote method. See [Passing multiple parameters](https://developers.arcgis.com/javascript/latest/references/core/core/workers/Connection/#multiple-parameters) * section to pass more than one parameter to the remote method. * @param options - An object specifying additional options. * @returns A Promise that resolves to the result of the method of the worker. * @example * const controller = new AbortController(); * const signal = controller.signal; * * // invoke a function on a worker thread * connection.invoke("myLongRunningRemoteFunction", { someParameter: 10 }, { * signal * }) * .then((result) => { * console.log(result); * }) * .catch((error) => { * console.error(error); * }); * * // if the call it takes more than 10 secs, abort: * setTimeout(() => { * controller.abort(); * }, 10000); */ invoke<T = any>(methodName: string, data?: any, options?: InvokeOptions): Promise<T>; }