GEOG 863
GIS Mashups for Geospatial Professionals

8.3 Executing an asynchronous task


To see an example of executing an asynchronous geoprocessing task, we’re going to return to Esri’s 911 call hotspot sample that we looked at earlier for its demonstration of the DateTextBox dijit.  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.

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, which begins on line 129.  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.  And like we saw in the previous example, an object of the Spinner class is displayed.

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 (on lines 200-202) stores this message in a variable called err, then logs it to the browser console.

While a task is still pending, the promise will return a JobInfo object.  The progTest() function (on lines 196-198) demonstrates reading the jobStatus property of that object and logging it to the console.  If you open your browser console and 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 (on lines 177-194), which handles the successful resolution of the task.  The documentation of the submitJob() method is incorrect (as of FA17), in that it lists its promise’s return value as the same as the execute() method’s (an object with messages and results properties).  What it should say is that it returns a JobInfo object, 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 name of the parameter.  The method returns a promise whose payload is a ParameterValue object 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 Esri’s sandbox:

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.