Problem with Deferred(s) in Loop

4733
6
Jump to solution
05-27-2015 02:24 PM
JerryGarcia
Occasional Contributor II

The following code will execute fine with only one deferred, but more than one, 'all.then()' never executes.

(Overall, I am trying to validate a set of geometries to ensure they are not too big before adding to the map)

Any help would be very much appreciated.  Thanks!

var defListArray = [];
array.forEach(layer.featureSet.features, function (feat) {
    var geom = feat.geometry;                    
    defListArray.push(that.validateFieldSize(geom));
});
                
//var defList = new DeferredList(defListArray); //Does not work with DeferredList as well; same behavior

all(defListArray).then(lang.hitch(this, function (results) {   
    //PROBLEM: This code only executes when there is only one Deferred in array
    // I want to know when
    console.log('deferred list', results);
}));

//...//

validateFieldSize: function(fieldGeom){
    var that = this;
    var deferred = new Deferred();

    this.geometryService = new GeometryService(this.geometryServiceURL);
    this.geometryService.on('areas-and-lengths-complete', lang.hitch(this, 'showVerifyiedFieldGeometryResults', deferred));

   //setup the parameters for the areas and lengths operation
    var areasAndLengthParams = new AreasAndLengthsParameters();
    areasAndLengthParams.lengthUnit = GeometryService.UNIT_FOOT;
    areasAndLengthParams.areaUnit = GeometryService.UNIT_ACRES;
    areasAndLengthParams.calculationType = 'geodesic';
    this.geometryService.simplify([fieldGeom], function (simplifiedGeometries) {
        areasAndLengthParams.polygons = simplifiedGeometries;
        that.geometryService.areasAndLengths(areasAndLengthParams);
    });

   //deferred.resolve('QUICK RESOLVE'); //'all().then()' executes if I comment this line out...
    return deferred;
},
showVerifyiedFieldGeometryResults: function(deferred, results){
    var acres = Math.floor(results.result.areas[0]);

    //NOTE: Check acres to ensure the feature is not too big... code omitted...

    console.log('geometry results'); //this line always executes so it appears something is wrong with the Deferreds...
    deferred.resolve('Verified Field Size: ' + acres);              
}

0 Kudos
1 Solution

Accepted Solutions
BenFousek
Occasional Contributor III

I guess I don't understand why you need deferreds when the geom service methods return deferreds themselves. Something like:

var promises = [];

array.forEach(layer.featureSet.features, function (feat) {
  promises.push(this.geometryService.simplify([feat.geometry]));
}, this);

all(promises).then(callback, errback);

And the same for areasAndLengths.

View solution in original post

6 Replies
ReneRubalcava
Frequent Contributor

This looks confusing to me:

this.geometryService.on('areas-and-lengths-complete', lang.hitch(this, 'showVerifyiedFieldGeometryResults', deferred));

I don't see in the source or docs that hitch takes a 3rd parameter. It looks like you are trying to pass it as a token.

You could rewrite it like this:

this.geometryService.on('areas-and-lengths-complete', this.showVerifyiedFieldGeometryResults(deferred));
//updated
showVerifyiedFieldGeometryResults: function(deferred){
   return function(results) {
      var acres = Math.floor(results.result.areas[0]);
      //NOTE: Check acres to ensure the feature is not too big... code omitted...
      console.log('geometry results'); //this line always executes so it appears something is wrong with the Deferreds...
      deferred.resolve('Verified Field Size: ' + acres);
    }               
}

I would try that

0 Kudos
JerryGarcia
Occasional Contributor II

This code works, but with the same results and problem I am having.  This code may be cleaner, but it works the same as using lang.hitch.  Thanks.

0 Kudos
BenFousek
Occasional Contributor III

Jerry Garcia​ Looks like deferred hell to me. Here's my take on that problem all with 2 sever calls and no deferreds:

constructor: function () {
     this.geometryService = new GeometryService(this.geometryServiceURL);
     this.areasAndLengthParams = lang.mixin(new AreasAndLengthsParameters(), {
        lengthUnit: GeometryService.UNIT_FOOT,
        areaUnit: GeometryService.UNIT_ACRES,
        calculationType: 'geodesic'
     });
},


validate: function (layer) {
    var geometries = [];
    array.forEach(layer.featureSet.features, function (feat) {
        geometries.push(feat.geometry);
    });
    this.geometryService.simplify(geometries, lang.hitch(this, '_simplifyResult'), lang.hitch(this, '_simplifyError'));
},


_simplifyResult: function (results) {
    this.areasAndLengthParams.polygons = results;
    this.geometryService.areasAndLengths(this.areasAndLengthParams, lang.hitch(this, '_areasAndLengthsResult', results), lang.hitch(this, '_areasAndLengthsError'));
},
_simplifyError: function (error) {
    // handle error
},


_areasAndLengthsResult: function (simplifiedGeometries, results) {
    // i'm making a HUGE assumption here the array of areas is in the same order as geometries passed to areasAndLengths
    array.forEach(simplifiedGeometries, function (simpGeom, idx) {
        var acres = Math.floor(result.areas[idx]);
        // do your check here
    }, this);
},
_areasAndLengthsError: function (error) {
    // handle error
}

Also check out esri/geometry/geometryEngineAsync | API Reference | ArcGIS API for JavaScript . It's all on the client now.

0 Kudos
JerryGarcia
Occasional Contributor II

I agree this is a good approach, but I'd like to process one feature at a time.  I have additional verification rules I need to process on each feature before adding to the map.  I simplified the code for this example.  I'm really interested in finding out why the all.then() does not execute when I can see all of the deferreds in the array are resolved()?  But, it does execute, when there is only one deferred. Thanks!

0 Kudos
BenFousek
Occasional Contributor III

I guess I don't understand why you need deferreds when the geom service methods return deferreds themselves. Something like:

var promises = [];

array.forEach(layer.featureSet.features, function (feat) {
  promises.push(this.geometryService.simplify([feat.geometry]));
}, this);

all(promises).then(callback, errback);

And the same for areasAndLengths.

JerryGarcia
Occasional Contributor II

Thanks.  Your suggestion helped me figure it out. Passing a Deferred to the callback like this does not work called multiple times: this.geometryService.on('areas-and-lengths-complete', lang.hitch(this, 'showVerifyiedFieldGeometryResults', deferred)); Instead, this works: geometryService.areasAndLengths(params, function(results){ ... deferred.resolve(); }