Search code examples
jquerygetjson

getJSON running order


I'm fully aware that getJSON runs asynchronously however I'm having trouble understanding why my program is always returning the same data. I'm looping through a list of possible sites to query and using getJSON to return data then manipulating the data however on each iteration of my loop the data that I'm getting back seems to be the same. When running this code directly I get the expected value (not in a loop). There have been odd occasions when I've received the second or third set of data however I'm assuming that this is caused by the network being faster than usual.

var songObj;

for(i = 0; i < networks.length; i++)
{
    runJSON(networks[i],"track",false);

    songObj = [];

    $.when.apply($, deferreds).then(function() {
        songObj = ($.grep(songList, function(e){return e.artist == curSong[0].artist}));
        console.log(songList);
        imgCode  =  "<a href='" + songObj[0].link 
                 + "'><img id = 'spotifyLogo' src='images/spotify.jpg' alt='mIage'></a>";
        theValue = imgCode + "<br>"
                 + "Available on Spotify for " + songObj[0].price
                 + "<br> <br>";

        $("#songDisplay").append(theValue);
        deferreds = [], index;
    });
}

function runJSON(network,searchType,display){
    var URL  = returnURL(network,searchType,$('#song_field').val().split(' ').join("+"));

    var val  = $('#song_field').val();
    var data = {val: val}

    deferreds.push($.getJSON(URL, data, function(data){

        if(document.getElementById("box") !== "undefined" && display == true){
            clearScreen();
            createCols();
        }

        songList = [];
        eval(network + "(data);");

        if(display === true){
            for(i = 0; i < songList.length; i++)
            {   
                displayTrack(i);
            }
        }

        done = true; 

    }));
}

Solution

  • Your code says this:

    1. Start a bunch of asynchronous operations
    2. Wait for them all to complete ($.when.apply(...))
    3. Process the songList array

    http://api.jquery.com/jQuery.when/

    In the case where multiple Deferred objects are passed to jQuery.when(), the method returns the Promise from a new "master" Deferred object that tracks the aggregate state of all the Deferreds it has been passed. The method will resolve its master Deferred as soon as all the Deferreds resolve

    Each one of your asynchronous operations goes

    1. Clear out the songList array
    2. Add some data to the songList array

    So therefore your flow is going to go (for example; order may vary)

    • Clear out songList, add list 1 to songList
    • Clear out songList, add list 2 to songList
    • ...
    • Clear out songList, add list n to songList
    • Process songList

    i.e. whichever asynchronous operation happens to execute last clears out whatever was in there before and adds just its list.

    If you really want to stick to using your global songList variable, instead of clearing it out in each runJSON invocation, you could clear it out before the loop and then just append all the results into a long list. Or to keep them separate, have it as an array of arrays (for example).