require(["esri/core/workers/Connection"], (Connection) => { /* code goes here */ });
import Connection from "@arcgis/core/core/workers/Connection.js";
esri/core/workers/Connection
This class is used to execute remote methods located on the module loaded into a separate thread via the workers framework.
The 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() or broadcast() methods.
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, or JavaScript object handled by the structured clone algorithm, or a JavaScript Promise that resolves with one of them.
For example, let's create a simple worker that calculates the sum of an array of numbers.
// 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.
// 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);
});
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.
// 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.
// 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);
});
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,
a MessagePort,
or an ImageBitmap.
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
extended attribute). See also Transferable objects.
To transfer an object to the worker, use the transferList
parameter of the 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.
// 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 back from the returned buffer.
// 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);
});
Constructors
Method Overview
Name | Return Type | Summary | Class |
---|---|---|---|
Promise[] | A convenient method that invokes a method on each worker. | Connection | |
Closes the existing connection instance to workers. | Connection | ||
Promise | Invokes a method on the remote module loaded with the worker. | Connection |
Method Details
-
broadcast
broadcast(methodName, data, options){Promise[]}
-
A convenient method that invokes a method on each worker.
ParametersmethodName StringThe name of the remote method to invoke on all workers.
data *optionalThe unique parameter passed as argument of the remote method.
options ObjectoptionalAn object specifying additional options. See the object specification table below for the required properties of this object.
Specificationsignal AbortSignaloptionalAn AbortSignal to abort the executions of the remote method. If canceled, the promise will be rejected with an error named
AbortError
. See also AbortController.ReturnsType Description Promise[] An array of promises that resolves with the result of the execution on each worker.
-
Closes the existing connection instance to workers. Notifies all workers to destroy the connection instance and dispose the remote module.
-
Invokes a method on the remote module loaded with the worker.
ParametersSpecificationmethodName StringThe name of the method to be invoked in the script.
data *optionalThe unique parameter passed as argument of the remote method. See Passing multiple parameters section to pass more than one parameter to the remote method.
options ObjectoptionalAn object specifying additional options. See the object specification table below for the required properties of this object.
SpecificationtransferList Transferable[]optionalAn array of Transferable objects. Each transferable object in the array should have a corresponding entry in the data object. See Using transferables section for more information.
signal AbortSignaloptionalAn AbortSignal to abort the execution of the remote method. If canceled, the promise will be rejected with an error named
AbortError
. See also AbortController.ReturnsType Description Promise A Promise that resolves to the result of the method of the worker. Exampleconst 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);