Chris P
Chris P

Reputation: 43

Deferred Promise & Jquery

I read a lot of answers about deferred but cannot exactly find what I want.

The close piece of code is http://jsfiddle.net/UZzeC/

Difference in my code is that I want to call on "process" function inside the when. statement N number of times.

//Dynamically generated JSON list
var json_list = [
    {"id":"div1","name":"Google.com"},
    {"id":"div2","name":"eBay.com"}
    {"id":"div3","name":"Yahoo.com"},
    {"id":"div4","name":"Facebook.com"}
];

$.when(
    for (var i in json_list) {
        process(json_list[i].id, json_list[i].name),
    }
).done(function() {
    $('#global').text("OK"); }
) .fail(function() {
    $('#global').text("FAIL");
});

the end state will be the code connecting to multiple web services async and returning its progress when each comes back with data

Can I embed this loop like this? I saw some usage on "Apply" with when but not sure how it would work for me.

Upvotes: 0

Views: 205

Answers (3)

Roamer-1888
Roamer-1888

Reputation: 19288

Only in very exceptional circumstances (practically, never) should for(var i in arr) {...} be used to loop through an array. The reason is that an array may have properties other than its numeric array indices, that not even if(arr.hasOwnProperty(i)) will filter out.

For example :

var arr = ['A', 'B', 'C'];
arr.color = 'RED';

Now, loop through arr with for(var i in arr) and you will discover A, B, C, and RED. ie the array's members and its properties.

DEMO

To be guaranteed to address just the array members, loop with for(var i=0; i<arr.length; i++) {...}.

DEMO

So, you can do as follows :

var requests = [];
for(var i=0; i<json_list.length; i++) {
    requests.push(process(json_list[i].id, json_list[i].name));
}

$.when.apply(null, requests).then(function() {
    $('#global').text("OK");
}, function() {
    $('#global').text("FAIL");
});

You can also use the native Array.prototype.map() or jQuery.map() to loop through the original array and return a processed array. For compactness, the processed array can be passed anonymously to $.when, as follows :

$.when.apply(null, $.map(json_list, function(request) {
    return process(request.id, request.name);
}).get()).then(function() {
    $('#global').text("OK");
}, function() {
    $('#global').text("FAIL");
});

Upvotes: 2

danikaze
danikaze

Reputation: 1654

I think what you want to do is something like this... (supposing process return a $.Deferred().promise() object)

var requests = [];

for (var i=0; i<json_list.length; i++) {
    requests.push(process(json_list[i].id, json_list[i].name));
}

$.when.apply($, requests).then(
    function() { $('#global').text("OK"); },
    function() { $('#global').text("FAIL"); }
);

EDIT: Edited the code to iterate the array properly. I thought it was an object and used for..in, but you should use this way always ;)

Upvotes: 2

Alnitak
Alnitak

Reputation: 340055

  1. Don't use for .. in on arrays
  2. You can't substitute a for loop for a function parameter - JS doesn't work that way

Since your json_list is an array, you can just use .map to get a new array of Promises, one for for each entry in the original array:

var requests = json_list.map(function(l) {
    return func_returning_promise(l.id, l.name);
});

and then you can use Function.prototype.apply to pass this array of Promises to $.when as if they were individual parameters:

$.when.apply($, requests).then(okFunc, failFunc);

Upvotes: 0

Related Questions