0

I am calling a function that saves edits to a database and returns a dojo/Deferred. I found that I could not save all records at once and so I limited each call to only send 150 records at a time and simply chained several calls together using a for loop.

Every time this code runs, the first 150 records are successfully saved and the final batch of records are successfully saved. Any batches in between seem to be overwritten by the final batch.

Here is the code:

applyEdits : function(layer, adds, updates, deletes, editInterval) {

    adds = adds || [];
    updates = updates || [];
    deletes = deletes || [];

    var maxFeatures = Math.max(adds.length, updates.length, deletes.length);

    var editInterval = editInterval || 155;

    var deferred = new Deferred();
    deferred.resolve();

    for (var i = 0; i < maxFeatures; i+=editInterval) {

        var addGroup = adds.slice(i, i+editInterval);
        var updateGroup = updates.slice(i, i+editInterval);
        var deleteGroup = deletes.slice(i, i+editInterval);

        deferred = deferred.then(lang.hitch(this, function() {
            return layer.applyEdits(addGroup, updateGroup, deleteGroup).then(function() {
                console.log("success");
            }, function(error) {
                console.log(error);
            });
        }));
    }

    return deferred;

adds, updates, and deletes are all Array's of Object's. My guess is that because Array's store references, the references are being overwritten each time through the loop. I tried creating deep copies of the Array's before passing them to layer.applyEdits, but that had no effect.

Brian
  • 2,702
  • 5
  • 37
  • 71
  • Have a look at [Javascript closure inside loops - simple practical example](http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example). You like you need to preserve this` via `lang.hitch` you will need to preserve the `addGroup`, `updateGroup` and `deleteGroup` variables. – Bergi Jul 22 '13 at 20:00
  • @Bergi - thank you for pointing me to that other post. However, I was not able to directly apply the solution from that post to my situation. On the other hand, based on your comment regarding `lang.hitch` I was able to get my code working by passing `addGroup`, `updateGroup`, and `deleteGroup` as arguments to `lang.hitch`. I would agree that my question is covering a similar topic to the other post you provided, but I would not say it is a duplicate. If you would like to provide an answer to my question based on you comment please do so. – Brian Jul 22 '13 at 20:26

1 Answers1

0

the references are being overwritten each time through the loop

Exactly. Not because they are references to arrays though, just because they are values in variables that get overwritten. Check JavaScript closure inside loops – simple practical example for an example where the counter variable i gets overwritten. When the deferred callbacks are executed after the loop ran (and they do because they're asynchronous) the variables will only hold the value the have been assigned at last, i.e. in the last iteration.

To fix that, use a closure:

for (var i = 0; i < maxFeatures; i+=editInterval) (function() {
    var addGroup = adds.slice(i, i+editInterval);
    var updateGroup = updates.slice(i, i+editInterval);
    var deleteGroup = deletes.slice(i, i+editInterval);

    deferred = deferred.then(lang.hitch(this, function() {
        return layer.applyEdits(addGroup, updateGroup, deleteGroup).then(function() {
            console.log("success");
        }, function(error) {
            console.log(error);
        });
    }));
})();

It's more elegant to use the closed-over values as parameter of the closure function, passing them from outside. In your case, you even can bind them directly to the callback function (or use Dojo's lang.hitch for older browsers which does the same thing):

for (var i = 0; i < maxFeatures; i+=editInterval)
    deferred = deferred.then(function(addGroup, updateGroup, deleteGroup) {
        return layer.applyEdits(addGroup, updateGroup, deleteGroup).then(function() {
            console.log("success");
        }, function(error) {
            console.log(error);
        });
    }.bind(this, adds.slice(i, i+editInterval), updates.slice(i, i+editInterval), deletes.slice(i, i+editInterval)));
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375