Accessing the JS API via a web worker

6098
28
05-15-2017 02:51 PM
RobertHewlett
Occasional Contributor

I would like to offload some of the heavy lifting in a web app to a web worker.

It is a 2-3 second jank I would like gone.

Right now the web worker would still need access to parts of the API e.g. Extent and Polygon.

I have tried loading the init.js script via importScripts() but I still get errors.

Has anyone had any success with the ArcGIS JS-API inside a web worker ... not outside but inside. 

0 Kudos
28 Replies
RobertScheitlin__GISP
MVP Emeritus

Robert,

   I have tried in the past and came to the conclusion that you can not interact with the API inside a web worker. I have been able to do simple or even complex math or JS operations but not use esri classes.

ThomasSolow
Occasional Contributor III

It seems to me that importScripts is the right way to handle this.  JavaScript doesn't allow you to share between threads currently.

I would imagine that there are limitations to what can be imported, and it may be difficult to import the entire JS API for various reasons.  For instance the worker's global scope is different from the normal JavaScript global scope, and the JS API probably relies on the normal global scope in some places.

It may be possible to build the modules you need into a single file (Extent, Polygon, and all dependencies) and pull this in via importScripts, assuming there's no issues with those modules running in the worker's scope.  I don't know much about the details here though.

0 Kudos
ReneRubalcava
Frequent Contributor

If you are using 4x, there is a Worker framework in the API that we use for some of our internal processing of things like VectorTiles.

Connection | API Reference | ArcGIS API for JavaScript 4.3 

There are limitations to what currently works in a Worker, for example esri/request works in a Worker, but in 4.3, Authentication does not, unless you authenticate on the main thread first. You also can't pass Geometries from workers to the main thread, you need to convert them to JSON first, but if your main thread used a typed Collection to load that JSON, it could work.

In the future we'll try to add a sample or two on workers, as we can make sure other parts of the API can be loaded in workers.

RobertHewlett
Occasional Contributor

Thanks for all the responses.

I am using 4.3 and I have been staring at the frame work but hesitate 'jumping down the rabbit hole' if what I am trying to do is not possible. 

So, I have a couple of specific questions:

1.) Would I be able to do the following inside the worker:

require(["esri/geometry/geometryEngine", "esri/geometry/Extent", "esri/geometry/Polygon" ], someFunctionInTheWorker)

2.) Is the worker a true worker and what I mean here is, can I still use postMessage() and onmessage?

I would like to send a progress message back several times before I send the final result.

3.) If I serialize to JSON will I get everything back on the other side. For example, will a polygon object still have a centroid

Rob

0 Kudos
KristianEkenes
Esri Regular Contributor

Here are my responses to these three questions:

1. Yes you can reference API modules in the worker. I have definitely used geometryEngine, jsonUtils, and promiseUtils in a worker loaded from the JSAPI. But I would use define() instead of require().

2. I don't know.   cc\ odoe ubatsukh-esristaff

3. Yes. I serialized Graphics in a worker (including the geometries) and got everything back.

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Was this possible in 3.x?

0 Kudos
KristianEkenes
Esri Regular Contributor

I'm not sure. I've only played around with this in 4.x.

0 Kudos
ReneRubalcava
Frequent Contributor

The client doesn't have access to the created worker, so you can't add event listeners to listen to messages. I can check if there is some other route for that or if we can expose it in some manner.

Here is a sample using a worker to buffer the centroid of the view extent.

index.html · GitHub 

0 Kudos
RobertHewlett
Occasional Contributor

You mentioned Graphic.

However, when I add 

    "esri/Graphic"

To my define define:

define([
    "esri/config",
    "esri/core/promiseUtils",
    "esri/geometry/geometryEngine",
    "esri/geometry/Extent",
    "esri/geometry/Polygon",
    "esri/Graphic"
], work);

I get an error in the worker.

ErrorEvent {isTrusted: true, message: "Uncaught TypeError: Cannot read property 'compatMode' of null", filename: "http://js.arcgis.com/4.3/dojo/dojo.js", lineno: 168, colno: 316}

Any ideas?

0 Kudos