@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
TypeScript
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>;
}