1

I have list of names separated by comma. What I want is I want to call server request for all names in a sequence and store result inside an array. I tried and it's working when I do have number of names which are there in string.

See Here - This is working when I know number of names

Now what I want is I want to make this code as generic. If I add one name in that string, It should handle automatically without adding any code for ajax request.

See Here - This is what I've tried. It's not working as expected.

shoppingList = shoppingList.split(",");
var result = [];

function fetchData(shoppingItem)
{
    var s1 = $.ajax('/items/'+shoppingItem);
    s1.then(function(res) {
        result.push(new Item(res.label,res.price));
        console.log("works fine");
    });
    if(shoppingList.length == 0)
    {
        completeCallback(result);
    }
    else
    {
        fetchData(shoppingList.splice(0,1)[0]);
    }
}

fetchData(shoppingList.splice(0,1)[0]);

Problem

I am not getting how to detect that all promise object have been resolved so that I can call callback function.

Jay Shukla
  • 5,794
  • 8
  • 33
  • 63
  • Notice the [deferred antipattern](http://stackoverflow.com/q/23803743/1048572) in your first solution, it should be just http://jsfiddle.net/obkp6Lg0/5/ – Bergi Dec 16 '14 at 08:22

3 Answers3

1

To make the ajax requests in sequence, you have to put the recursive call in the callback:

function fetchList(shoppingList, completeCallback) {
    var result = [];
    function fetchData() {
        if (shoppingList.length == 0) {
            completeCallback(result);
        } else {
            $.ajax('/items/'+shoppingList.shift()).then(function(res) {
                result.push(new Item(res.label,res.price));
                console.log("works fine");
                fetchData();
//              ^^^^^^^^^^^
            });
        }
    }
    fetchData();
}

or you actually use promises and do

function fetchList(shoppingList) {
    return shoppingList.reduce(function(resultPromise, shoppingItem) {
        return resultPromise.then(function(result) {
            return $.ajax('/items/'+shoppingItem).then(function(res) {
                result.push(new Item(res.label,res.price));
                return result;
            });
        });
    }, $.when([]));
}

(updated jsfiddle)


Notice there is nothing in the requirements of the task about the ajax requests to be made sequentially. You could also let them run in parallel and wait for all of them to finish:

function fetchList(shoppingList) {
    $.when.apply($, shoppingList.map(function(shoppingItem) {
        return $.ajax('/items/'+shoppingItem).then(function(res) {
            return new Item(res.label,res.price);
        });
    })).then(function() {
        return Array.prototype.slice.call(arguments);
    })
}

(updated jsfiddle)

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • It looks correct but I find it very complex to understand. Can you please update my fiddle code so that I can understand. I want to use second approach. – Jay Shukla Dec 16 '14 at 08:16
0
// global:
var pendingRequests = 0;

// after each ajax request:
pendingRequests++;

// inside the callback:
if (--pendingRequest == 0) {
    // all requests have completed
}
Doug Leary
  • 199
  • 8
  • It's same as checking length of array which I did. I don't think it will help. Can you please update my fiddle and show me how will it work? – Jay Shukla Dec 16 '14 at 07:59
0

I have modified your code to minimal to make it work - Click here.

Please note your last assertion will fail as the item promise is not resolved in linear manner. Thus sequence of the item will change.

Kunal Shewale
  • 696
  • 6
  • 17