XMLHttpRequest calls not finishing before return statement so undefined-Collection of common programming errors

I’m attempting to count how many items total are in the database I’m querying. It’s third party so it’s cross domain XMLHttpRequests but I’m making the method in a Chrome Extension and the permissions bit in the manifest.json let’s it work nicely.

The problem I seem to be having is this: I’m looping through a list of categories and counting the amount in each before the XMLHttpRequests are coming back from the external server. The methods are started by the press of a button of id=”countButton”. Here’s the relevant javascript/jQuery:

//simple listener for the button
document.getElementById('countButton').addEventListener('click', function() runTotalCount()}, true);

//loops through a list of categories in a drop down with values 0-36
function runTotalCount(){
    var sum = 0;
    $('#categorySelect option').each(function(){
        var value = $(this).val();
        sum += retrieveCategoryCount(value);
        alert("New Sum = " + sum);
    });
    var total = "
Total items in Sum is " + sum + "

"; document.getElementById('results').innerHTML = total; } //actually makes the request and sums the items count for each category //the server response is a json with an alphabetized "items" per category function retrieveCategoryCount(num){ var sum = 0; var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(){ if (xhr.readyState == 4 && xhr.status == 200){ var str = xhr.responseText; alert("str = " + str); var json = $.parseJSON(str); alert("JSON = " + json); for(item in json.alpha){ alert("items count = " + json.alpha[item].items); sum += json.alpha[item].items; } alert("Category Sum = " + sum); return sum; } } xhr.open( "GET", "http://services.runescape.com/m=itemdb_rs/api/catalogue/category.json?category=" + num, true); xhr.send(null); }

As it is the stuff within the onreadystate for retrieveCategoryCount never gets called because the XMLHttpRequests are still pending by the time the function finishes. On synchronous calls the alert("Category Sum = " + sum); returns the right number but then the function return just below it is NaN (I’d rather not hang up the browser though so asynchronous is what I’d prefer for a solution).

What needs to change to properly get the item count? Thanks in advance.

UPDATE: I’ve also tried code for retrieveCategoryCount of this:

function retrieveCategoryCount(num){
    var sum = 0;
    $.getJSON("http://services.runescape.com/m=itemdb_rs/api/catalogue/category.json?category=" + num, function(data){
        for(item in data.alpha){
            alert("items count = " + data.alpha[item].items);
            sum += data.alpha[item].items;
        }
    alert("Category Sum = " + sum);
    return sum;
    });
}

The problem here is that the callback never gets run because the request is still pending by the time the value returned from the function is added to “sum”.

  1. You can put the code that should happen AFTER the async call completes into a callback function and pass that into your async function, then have it callback.

    var sum = 0,
        setTotalCount = function(data){ 
            .. stuff to set the dom element based on callback
        };
    $('#categorySelect option').each(function(){
        var value = $(this).val();
        retrieveCategoryCount(value, setTotalCount);
    });
    
    
    function retrieveCategoryCount(num, callback){
    var sum = 0;
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function(){
        if (xhr.readyState == 4 && xhr.status == 200){
            var str = xhr.responseText;
            alert("str = " + str);
            var json = $.parseJSON(str);
            alert("JSON = " + json);
            for(item in json.alpha){
                alert("items count = " + json.alpha[item].items);
                sum += json.alpha[item].items;
            }
        alert("Category Sum = " + sum);
           callback(sum); // callback the function you passed in
        }
    }
    xhr.open(
        "GET",
        "http://services.runescape.com/m=itemdb_rs/api/catalogue/category.json?category=" + num,
        true);
    xhr.send(null);
    }
    
  2. The callback function you pass to onreadystatechange is not retrieveCategoryCount. It’s return value is lost because the function is only called in response to the readystatechange event.

    Do what you need to do with the data in the callback. Don’t try to return the data.

Originally posted 2013-11-09 19:45:38.