GEOG 863:
Web Application Development for Geospatial Professionals

8.3 Executing an Asynchronous Task


8.3 Executing an Asynchronous Task

To see an example of executing an asynchronous geoprocessing task, we’re going to return to the example based on Esri’s 911 call hotspot sample that we looked at earlier when discussing date picker controls. This service uses the Hot Spot Analysis tool to identify areas of statistically significant high and low 911 call frequency based on a small sampling of data from a community in Oregon.

See the Pen 911 Hotspot Analysis by Jimmy Kroon (@JimmyKroon) on CodePen.

The documentation of the service utilized in this sample tells us that its 911 Calls Hotspot task has just one input parameter: Query, a string defining the days of the week or a date range to use in the analysis. It has two outputs: Output_Features, a FeatureSet of the points selected by the Query parameter, and Hotspot_Raster, the raster created by the Hot Spot Analysis tool.

Preparing the input parameter

Clicking on the Analyze 911 Calls button triggers the findHotspot() function. As we saw in the synchronous example, an object variable called params is set up to hold the input parameters. In this case, Query is the only parameter and its value is set to the return value from a function called buildDefinitionQuery()

buildDefinitionQuery() obtains the user-selected dates, as we discussed last lesson, then uses string concatenation to build a SQL where clause that will select the calls in the date range. 

The date range expression is actually just the first part of a compound expression, with the second part being an expression that selects calls on particular days of the week. Note the clever way that the defQuery string is constructed. Each piece of the compound expression is added to an array. Then the array method join() is used to join together each of the pieces with the string " AND " inserted after each piece (except the last one). 

Running the task

Returning to the findHotspot() function, after defining the input parameter, a call is made to a function called cleanup(), which removes the hotspot layer in the event it was already added to the map in an earlier running of the task.

Because the task being consumed here is asynchronous, it is run using the Geoprocessor.submitJob() method. As with the execute() method, submitJob() returns a promise that is handled with the then() method. Unlike the previous example which only handled the promise resolving successfully, the hotspot sample also includes handlers for the promise’s rejected (errBack) and pending states (progTest).

In the case of a failure, the promise passes along an error message to the errBack() function. Note that the function stores this message in a variable called error, then inserts it into a label element in the sidebar and logs it to the browser console.

While a task is still pending, the promise will return a JobInfo object. The progTest() function demonstrates reading the jobStatus property of that object and logging it to the console. If you test the app, you should see the messages "job-submitted", "job-executing", and "job-succeeded", all produced as a result of the progTest() function. The JobInfo will be passed to the pending function callback function every 1000 milliseconds by default, though this can be overridden by setting the Geoprocessor’s updateDelay property.

Processing the task’s response

Now let’s look at the drawResultData() function, which handles the successful resolution of the task. The documentation of the submitJob() method notes that the method returns a JobInfoobject, the same object type sent to the pending callback function. In this sample, the JobInfo object is stored in a variable called result.

Once a task has resolved successfully, the Geoprocessor object offers three methods for working with the task’s results: getResultData(), getResultImage() and getResultMapImageLayer(). The sample demonstrates usage of the latter. The jobId property is read and supplied to the getResultMapImageLayer() method. The returned layer then has its opacity and title set before being added to the map.

Note that the ImageParameters object created on line 179 isn’t actually used in the sample. Creating that object would make sense if you were going to use the getResultImage() method, as it could be used to specify the desired parameters of the returned image.

Finally, a word about the getResultData() method. Recall that the task has an output parameter called Output_Features, which is the FeatureSet of points that was used in the analysis. getResultData() can be used to work with this FeatureSet by specifying the jobId and the nameof the parameter. The method returns a promise whose payload is a ParameterValueobject like we saw in the synchronous example. To see the method in use, try inserting the following code at the top of the drawResultData() function in CodePen:

gp.getResultData(result.jobId, "Output_Features").then(function(data){
  console.log("Analyzed " + data.value.features.length + " points");

That brings us to the end of the content on consuming geoprocessing services. Move on to the next page for the assignment that will assess your ability to apply what you learned from the lesson.