1

I work with jQuery and Deferred and there is an (for me) unexpected behavior. I hope you can explain it to me.

What i plan to do is: I want to iterate over a list of keys. For every key I create an deferred and call a function (doSomething), where i pass the key and a callback method (where I resolve the deferred). After the call I add the deferred to a list. The function doSomething does something async and calls at the end the overgiven callback method. After the iteration, I await the deferreds and display some alerts.

The following snippet was my first try, but it isn't working correct. I expected three alerts with '0', '1' and 'first,second'. But I only get '1'.

var doSomething = function(key, callback) {
    window.setTimeout(function() {
        callback(key);
    }, 0)
}

var items = new Array();
var processes = new Array();
var keys = ['first', 'second'];

for (var idx in keys) {
    var deferred = $.Deferred();

    doSomething(keys[idx], function(item) {
        items.push(item);
        deferred.resolve();
    });

    processes.push(deferred.promise());
}

processes[0].done(function() {
    alert('0');
})

processes[1].done(function() {
    alert('1');
})

$.when.apply($, processes).done(function() {
    alert(items);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>

The second try was without the async call in doSomething and now I get all three alerts.

var doSomething = function(key, callback) {
    callback(key);
}

var items = new Array();
var processes = new Array();
var keys = ['first', 'second'];

for (var idx in keys) {
    var deferred = $.Deferred();

    doSomething(keys[idx], function(item) {
        items.push(item);
        deferred.resolve();
    });

    processes.push(deferred.promise());
}

processes[0].done(function() {
    alert('0');
})

processes[1].done(function() {
    alert('1');
})

$.when.apply($, processes).done(function() {
    alert(items);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>

The last try was with an async call in doSomething and do the work in a 'seperate' function called func. This gets me the expected three alerts.

var doSomething = function(key, callback) {
    window.setTimeout(function() {
        callback(key);
    }, 0)
}

var items = new Array();
var processes = new Array();
var keys = ['first', 'second'];

var func = function(key) {
    var deferred = $.Deferred();

    doSomething(key, function(item) {
        items.push(item);
        deferred.resolve();
    });

    return deferred.promise();
}

for (var idx in keys) {
    processes.push(func(keys[idx]));
}

processes[0].done(function() {
    alert('0');
})

processes[1].done(function() {
    alert('1');
})

$.when.apply($, processes).done(function() {
    alert(items);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>

So my question is: Why does my first try not working like expected? I can't explain why.

Ralf J.
  • 11
  • 1
  • Possible duplicate of [JavaScript closure inside loops – simple practical example](http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) (and many others). – Roamer-1888 Jun 01 '16 at 21:42

0 Answers0