简体   繁体   中英

AJAX callbacks when getting multiple XML files

I'm trying to get a better understanding of how callbacks work.

In this example, I want to get two or more XML files using AJAX, then extract the content I need from them, and then store that data in an array outside of the AJAX call. I want to use the "dataExt" array to plot a google chart, but I am getting hung up implementing callbacks properly. I guess my brain just isn't big enough yet!

Here's my code snippet.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>

   // List of xml files.
   var xmlFeed = ['rss-feed1.xml', "rss-feed2.xml"];

  // An array to store each "dataString" from each XML file.
   var dataExt = [];

    for(var i = 0; i < xmlFeed.length; i++) {

        $.ajax({
        type: "GET",
        dataType: "xml",
        async: true,
        url: xmlFeed[i],
        contentType: "text/xml; charset=UTF-8",
        success: function(xml){

            var content = $(xml).find("content");
            var dataString = (content.text());
            console.log(dataString);

            // Need to push "dataString" to "dataExt" array.
            // dataExt = dataExt.push(dataString); <-- this doesn't work 

            }  

        }) // close ajax    
    } // close loop

    console.log(dataExt[0]);
    console.log(dataExt[1]);

</script>

When you make an AJAX request, the call to $.ajax() returns immediately. It does not wait around for the content to come back over the network. In your example, the console.log() statements are being called before the callbacks have been completed.

What you want is a single callback that gets executed once all the data you need from your various requests has been fetched. To do this you need some sort of synchronization between the various AJAX calls that you're doing. jQuery alone doesn't support this that well.

You can roll this yourself. However, this is a common enough design problem that whole libraries have been written to handle it.

Do some Googling on the Promise pattern. Once you've done that, have a look at the Q library, which is one of several implementations of the pattern. They have done most of the hard work of synchronizing multiple AJAX requests for you.

Example:

function xmlPromise(name) {
    return Q.promise(function (resolve, reject, notify) {
        $.ajax({
            type: "GET",
            dataType: "xml",
            async: true,
            url: name,
            contentType: "text/xml; charset=UTF-8"
        })        
       .done(function (data) {
           resolve(data);
        }).fail(function () {
            reject();
        });
    });
};

var promises = [ xmlPromise('1.xml'), xmlPromise('2.xml') ];

var results = [];

Q.allSettled(promises).then(function(responses) {
    console.log(responses[0].value);
    console.log(responses[1].value);

    results.push(responses[0].value);
    results.push(responses[1].value);
});

In this example, the xmlPromise() function creates a promise object for you based on the URL you want to fetch. This promise represents a unit of work that will be completed at some time in the future. When the AJAX call you create in the promise returns successfully, it calls the resolve() method which lets Q know that the promise has been fulfilled, and the data is ready for use.

Once the promises are constructed, we pass an array of them into Q.allSettled(), which actually fires off the requests. Because these requests are asynchronous, they are executed in parallel. Once all of the promises either resolved or been rejected, Q will call the function you pass into the then() method, and pass in the results of your AJAX calls.

in original example console logs are fired before request finishes.

hope this example is what you mean:

function getXml(file, successCallback){
    $.ajax({
        type: "GET",
        dataType: "xml",
        async: true,
        url: file,
        contentType: "text/xml; charset=UTF-8",
        success: successCallback

        }) // close ajax  
    }

    function sc(xml){
            var content = $(xml).find("content");
            var dataString = (content.text());
            console.log(dataString);

            // Need to push "dataString" to "dataExt" array.
            // dataExt = dataExt.push(dataString); <-- this doesn't work 

           // do whatever else you want next

    }

    pages ['1.xml', '2.xml'].forEach(function(v, i){
        getXml(v, sc);
    })

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM